ZQuest Classic Coverage Report


Directory: src/
File: src/zq/zq_tiles.cpp
Date: 2025-12-07 03:15:32
Exec Total Coverage
Lines: 99 7550 1.3%
Functions: 1 199 0.5%
Branches: 14 6777 0.2%

Line Branch Exec Source
1 #include <cstring>
2 #include <cmath>
3
4 #include "allegro/color.h"
5 #include "base/files.h"
6 #include "base/pal_tables.h"
7 #include "base/qrs.h"
8 #include "base/dmap.h"
9 #include "base/cpool.h"
10 #include "base/autocombo.h"
11 #include "base/packfile.h"
12 #include "base/gui.h"
13 #include "base/combo.h"
14 #include "base/msgstr.h"
15 #include "base/zdefs.h"
16 #include "new_subscr.h"
17 #include "subscr.h"
18 #include "zq/zq_tiles.h"
19 #include "zq/zquest.h"
20 #include "tiles.h"
21 #include "zq/zq_misc.h"
22 #include "zq/zq_class.h"
23 #include "base/zsys.h"
24 #include "base/colors.h"
25 #include "base/qst.h"
26 #include "gui/jwin.h"
27 #include <base/new_menu.h>
28 #include "base/jwinfsel.h"
29 #include "hero_tiles.h"
30 #include "zq/questReport.h"
31 #include "dialog/info.h"
32 #include "dialog/scaletile.h"
33 #include "dialog/rotatetile.h"
34 #include "dialog/alert.h"
35 #include "drawing.h"
36 #include "colorname.h"
37 #include "zq/render.h"
38 #include "zinfo.h"
39 #include <fmt/format.h>
40 #include <functional>
41 #include "zq/moveinfo.h"
42 using std::set;
43
44
45 #ifdef _MSC_VER
46 #define stricmp _stricmp
47 #endif
48
49 #define HIDE_USED (show_only_unused_tiles&1)
50 #define HIDE_UNUSED (show_only_unused_tiles&2)
51 #define HIDE_BLANK (show_only_unused_tiles&4)
52 #define HIDE_8BIT_MARKER (show_only_unused_tiles&8)
53
54 extern void large_dialog(DIALOG *d);
55 static void massRecolorReset4Bit();
56 static void massRecolorReset8Bit();
57 static bool massRecolorSetup(int32_t cset);
58 static void massRecolorApply(int32_t tile);
59 extern int32_t last_droplist_sel;
60 extern int32_t TilePgCursorCol, CmbPgCursorCol;
61
62 int32_t ex=0;
63 int32_t nextcombo_fake_click=0;
64 int32_t invcol=0;
65 int32_t tthighlight = 1;
66 int32_t showcolortip = 1;
67 int32_t show_quartgrid = 0, hide_grid = 0;
68
69 tiledata *newundotilebuf;
70 std::vector<newcombo> undocombobuf;
71
72 BITMAP *selection_pattern;
73 byte selection_grid[18][18];
74 byte selection_anchor=0;
75
76 enum {selection_mode_normal, selection_mode_add, selection_mode_subtract, selection_mode_exclude};
77 BITMAP *selecting_pattern;
78 int32_t selecting_x1, selecting_x2, selecting_y1, selecting_y2;
79
80 BITMAP *intersection_pattern;
81
82 byte relational_template[48][4]=
83 {
84 { 0, 0, 0, 0 },
85 { 0, 1, 0, 0 },
86 { 1, 0, 0, 0 },
87 { 1, 1, 0, 0 },
88 { 0, 0, 1, 0 },
89 { 0, 1, 1, 0 },
90 { 1, 0, 1, 0 },
91 { 1, 1, 1, 0 },
92 { 0, 0, 0, 1 },
93 { 0, 1, 0, 1 },
94 { 1, 0, 0, 1 },
95 { 1, 1, 0, 1 },
96 { 0, 0, 1, 1 },
97 { 0, 1, 1, 1 },
98 { 1, 0, 1, 1 },
99 { 1, 1, 1, 1 },
100 { 0, 2, 0, 2 },
101 { 1, 2, 0, 2 },
102 { 0, 2, 1, 2 },
103 { 1, 2, 1, 2 },
104 { 3, 3, 0, 0 },
105 { 3, 3, 1, 0 },
106 { 3, 3, 0, 1 },
107 { 3, 3, 1, 1 },
108 { 3, 4, 0, 2 },
109 { 3, 4, 1, 2 },
110 { 2, 0, 2, 0 },
111 { 2, 1, 2, 0 },
112 { 2, 0, 2, 1 },
113 { 2, 1, 2, 1 },
114 { 2, 2, 2, 2 },
115 { 4, 3, 2, 0 },
116 { 4, 3, 2, 1 },
117 { 4, 4, 2, 2 },
118 { 0, 0, 3, 3 },
119 { 0, 1, 3, 3 },
120 { 1, 0, 3, 3 },
121 { 1, 1, 3, 3 },
122 { 0, 2, 3, 4 },
123 { 1, 2, 3, 4 },
124 { 3, 3, 3, 3 },
125 { 3, 4, 3, 4 },
126 { 2, 0, 4, 3 },
127 { 2, 1, 4, 3 },
128 { 2, 2, 4, 4 },
129 { 4, 3, 4, 3 },
130 { 4, 4, 4, 4 },
131 { 5, 5, 5, 5 }
132 };
133
134 byte dungeon_carving_template[96][4]=
135 {
136 { 0, 0, 0, 0 },
137 { 0, 1, 0, 0 },
138 { 1, 0, 0, 0 },
139 { 1, 1, 0, 0 },
140 { 0, 0, 1, 0 },
141 { 0, 1, 1, 0 },
142 { 1, 0, 1, 0 },
143 { 1, 1, 1, 0 },
144 { 0, 0, 0, 1 },
145 { 0, 1, 0, 1 },
146 { 1, 0, 0, 1 },
147 { 1, 1, 0, 1 },
148 { 0, 0, 1, 1 },
149 { 0, 1, 1, 1 },
150 { 1, 0, 1, 1 },
151 { 1, 1, 1, 1 },
152 { 0, 2, 0, 2 },
153 { 1, 2, 0, 2 },
154 { 0, 2, 1, 2 },
155 { 1, 2, 1, 2 },
156 { 3, 3, 0, 0 },
157 { 3, 3, 1, 0 },
158 { 3, 3, 0, 1 },
159 { 3, 3, 1, 1 },
160 { 3, 4, 0, 2 },
161 { 3, 4, 1, 2 },
162 { 2, 0, 2, 0 },
163 { 2, 1, 2, 0 },
164 { 2, 0, 2, 1 },
165 { 2, 1, 2, 1 },
166 { 2, 2, 2, 2 },
167 { 4, 3, 2, 0 },
168 { 4, 3, 2, 1 },
169 { 4, 4, 2, 2 },
170 { 0, 0, 3, 3 },
171 { 0, 1, 3, 3 },
172 { 1, 0, 3, 3 },
173 { 1, 1, 3, 3 },
174 { 0, 2, 3, 4 },
175 { 1, 2, 3, 4 },
176 { 3, 3, 3, 3 },
177 { 3, 4, 3, 4 },
178 { 2, 0, 4, 3 },
179 { 2, 1, 4, 3 },
180 { 2, 2, 4, 4 },
181 { 4, 3, 4, 3 },
182 { 4, 4, 4, 4 },
183 { 5, 5, 5, 5 },
184
185 { 5, 5, 5, 5 },
186 { 6, 6, 6, 6 },
187 { 7, 7, 7, 7 },
188 { 7, 6, 7, 6 },
189 { 8, 8, 8, 8 },
190 { 16, 6, 8, 15 },
191 { 7, 7, 8, 8 },
192 { 7, 6, 8, 15 },
193 { 9, 9, 9, 9 },
194 { 6, 6, 9, 9 },
195 { 7, 17, 14, 9 },
196 { 7, 6, 14, 9 },
197 { 8, 9, 8, 9 },
198 { 16, 6, 8, 9 },
199 { 7, 17, 8, 9 },
200 { 7, 6, 8, 9 },
201 { 10, 10, 10, 10 },
202 { 7, 10, 14, 10 },
203 { 16, 10, 8, 10 },
204 { 7, 10, 8, 10 },
205 { 11, 11, 11, 11 },
206 { 11, 11, 8, 15 },
207 { 11, 11, 14, 9 },
208 { 11, 11, 8, 9 },
209 { 14, 14, 14, 14 },
210 { 14, 14, 8, 14 },
211 { 12, 12, 12, 12 },
212 { 12, 6, 12, 15 },
213 { 12, 17, 12, 9 },
214 { 12, 6, 12, 9 },
215 { 12, 10, 12, 10 },
216 { 15, 15, 15, 15 },
217 { 15, 15, 15, 9 },
218 { 15, 14, 12, 10 },
219 { 13, 13, 13, 13 },
220 { 16, 6, 13, 13 },
221 { 7, 17, 13, 13 },
222 { 7, 6, 13, 13 },
223 { 16, 16, 16, 16 },
224 { 7, 16, 16, 16 },
225 { 11, 11, 13, 13 },
226 { 11, 14, 13, 16 },
227 { 17, 17, 17, 17 },
228 { 17, 6, 17, 17 },
229 { 12, 10, 17, 16 },
230 { 15, 11, 17, 13 },
231 { 15, 14, 17, 16 },
232 { 18, 18, 18, 18 }
233 };
234
235 struct tile_move_data
236 {
237 int32_t copies;
238 int32_t dest_first;
239 int32_t dest_last;
240 int32_t src_first;
241 int32_t src_last;
242 int32_t dest_top;
243 int32_t dest_bottom;
244 int32_t src_top;
245 int32_t src_bottom;
246 int32_t src_left, src_right;
247 int32_t src_width, src_height;
248 int32_t dest_left, dest_right;
249 int32_t dest_width, dest_height;
250 int32_t rows, cols;
251 bool rect, move;
252
253 tile_move_data()
254 {
255 copies = dest_first = dest_last = src_first = src_last = dest_top =
256 dest_bottom = src_top = src_bottom = src_left = src_right =
257 src_width = src_height = dest_left = dest_right = dest_width =
258 dest_height = rows = cols = 0;
259 rect = move = false;
260 }
261
262 tile_move_data(tile_move_data const& other)
263 {
264 copy(other);
265 }
266
267 tile_move_data& operator=(tile_move_data const& other)
268 {
269 copy(other);
270 return *this;
271 }
272
273 void copy(tile_move_data const& other)
274 {
275 copies = other.copies;
276 dest_first = other.dest_first;
277 dest_last = other.dest_last;
278 src_first = other.src_first;
279 src_last = other.src_last;
280 dest_top = other.dest_top;
281 dest_bottom = other.dest_bottom;
282 src_top = other.src_top;
283 src_bottom = other.src_bottom;
284 src_left = other.src_left;
285 src_right = other.src_right;
286 src_width = other.src_width;
287 src_height = other.src_height;
288 dest_left = other.dest_left;
289 dest_right = other.dest_right;
290 dest_width = other.dest_width;
291 dest_height = other.dest_height;
292 rows = other.rows;
293 cols = other.cols;
294 rect = other.rect;
295 move = other.move;
296 }
297
298 void flip()
299 {
300 zc_swap(src_first, dest_first);
301 zc_swap(src_last, dest_last);
302 zc_swap(src_top, dest_top);
303 zc_swap(src_bottom, dest_bottom);
304 zc_swap(src_left, dest_left);
305 zc_swap(src_right, dest_right);
306 zc_swap(src_width, dest_width);
307 zc_swap(src_height, dest_height);
308 }
309 };
310 bool do_movetile_united(tile_move_data const& tmd);
311
312 struct combo_move_data
313 {
314 int32_t tile, tile2, copy1, copycnt;
315 combo_move_data() : tile(0), tile2(0), copy1(0), copycnt(0){}
316 combo_move_data(combo_move_data const& other)
317 {
318 copy(other);
319 }
320 combo_move_data& operator=(combo_move_data const& other)
321 {
322 copy(other);
323 return *this;
324 }
325 void copy(combo_move_data const& other)
326 {
327 tile = other.tile;
328 tile2 = other.tile2;
329 copy1 = other.copy1;
330 copycnt = other.copycnt;
331 }
332
333 void flip()
334 {
335 int32_t tcnt = tile2-tile+1;
336 int32_t cpy2 = copy1+copycnt-1;
337 zc_swap(tile,copy1);
338 tile2 = cpy2;
339 copycnt = tcnt;
340 }
341 };
342
343 bool do_movecombo(combo_move_data const& cmd, ComboMoveUndo& on_undo, bool is_undoing = false);
344 static optional<ComboMoveUndo> last_combo_move_list;
345 static optional<TileMoveUndo> last_tile_move_list;
346
347 int refl_flags = 0;
348 enum
349 {
350 REFL_90CW, REFL_HFLIP,
351 REFL_90CCW, REFL_VFLIP,
352 REFL_180, REFL_DBLFLIP,
353 REFL_MAX
354 };
355 const char *reflbtn_names[] =
356 {
357 "90 CW", "HFlip",
358 "90 CCW", "VFlip",
359 "180 Rot", "Diag Flip"
360 };
361 int bgmode = 0, xmode = 0;
362 const char *bgmodebtn_names[] =
363 {
364 "BG Color 0", "BG Trans."
365 };
366 const char *xmodebtn_names[] =
367 {
368 "X", "No X"
369 };
370 enum
371 {
372 XMODE_X, XMODE_NOX,
373 XMODE_MAX
374 };
375 enum
376 {
377 BGMODE_0, BGMODE_TRANSP,
378 BGMODE_MAX
379 };
380
381 void merge_tiles(int32_t dest_tile, int32_t src_quarter1, int32_t src_quarter2, int32_t src_quarter3, int32_t src_quarter4)
382 {
383 int32_t size=tilesize(newtilebuf[dest_tile].format)>>4;
384 int32_t size2=size>>1;
385
386 if(newtilebuf[dest_tile].data==NULL)
387 {
388 reset_tile(newtilebuf, dest_tile, newtilebuf[src_quarter1>>2].format);
389 }
390
391 int32_t i=0;
392
393 if((dest_tile<<2)+i!=src_quarter1)
394 {
395 for(int32_t j=0; j<8; ++j)
396 {
397 memcpy(&(newtilebuf[dest_tile].data[((j+((i&2)<<2))*size)+((i&1)*size2)]), &(newtilebuf[src_quarter1>>2].data[((j+((src_quarter1&2)<<2))*size)+((src_quarter1&1)*size2)]), size2);
398 }
399 }
400
401 i=1;
402
403 if((dest_tile<<2)+i!=src_quarter2)
404 {
405 for(int32_t j=0; j<8; ++j)
406 {
407 memcpy(&(newtilebuf[dest_tile].data[((j+((i&2)<<2))*size)+((i&1)*size2)]), &(newtilebuf[src_quarter2>>2].data[((j+((src_quarter2&2)<<2))*size)+((src_quarter2&1)*size2)]), size2);
408 }
409 }
410
411 i=2;
412
413 if((dest_tile<<2)+i!=src_quarter3)
414 {
415 for(int32_t j=0; j<8; ++j)
416 {
417 memcpy(&(newtilebuf[dest_tile].data[((j+((i&2)<<2))*size)+((i&1)*size2)]), &(newtilebuf[src_quarter3>>2].data[((j+((src_quarter3&2)<<2))*size)+((src_quarter3&1)*size2)]), size2);
418 }
419 }
420
421 i=3;
422
423 if((dest_tile<<2)+i!=src_quarter4)
424 {
425 for(int32_t j=0; j<8; ++j)
426 {
427 memcpy(&(newtilebuf[dest_tile].data[((j+((i&2)<<2))*size)+((i&1)*size2)]), &(newtilebuf[src_quarter4>>2].data[((j+((src_quarter4&2)<<2))*size)+((src_quarter4&1)*size2)]), size2);
428 }
429 }
430 }
431
432 static void make_combos(int32_t startTile, int32_t endTile, int32_t cs)
433 {
434 al_trace("inside make_combos()\n");
435 int32_t startCombo=0;
436
437 if(!select_combo_2(startCombo,cs))
438 return;
439
440 int32_t temp=combobuf[startCombo].o_tile;
441 combobuf[startCombo].set_tile(startTile);
442
443 if(!edit_combo(startCombo, false, cs))
444 {
445 combobuf[startCombo].set_tile(temp);
446 return;
447 }
448
449 go_combos();
450
451 for(int32_t i=0; i<=endTile-startTile; i++)
452 {
453 combobuf[startCombo+i]=combobuf[startCombo];
454 combobuf[startCombo+i].set_tile(startTile+i);
455 }
456
457 setup_combo_animations();
458 setup_combo_animations2();
459 }
460
461 static void make_combos_rect(int32_t top, int32_t left, int32_t numRows, int32_t numCols, int32_t cs)
462 {
463 int32_t startCombo=0;
464
465 if(!select_combo_2(startCombo, cs))
466 return;
467
468 int32_t startTile=top*TILES_PER_ROW+left;
469 int32_t temp=combobuf[startCombo].o_tile;
470 combobuf[startCombo].set_tile(startTile);
471
472 if(!edit_combo(startCombo, false, cs))
473 {
474 al_trace("make_combos_rect() early return\n");
475 combobuf[startCombo].set_tile(temp);
476 return;
477 }
478
479 bool smartWrap=false;
480 if(numCols!=4 && numRows>1)
481 {
482 char buf[64];
483 if(numCols<4)
484 sprintf(buf, "Limit to %d column%s?", numCols, numCols==1 ? "" : "s");
485 else
486 sprintf(buf, "Fit to 4 columns?"); // Meh, whatever.
487 int32_t ret=jwin_alert("Wrapping", buf, NULL, NULL, "&Yes", "&No", 'y', 'n', get_zc_font(font_lfont));
488 if(ret==1)
489 smartWrap=true;
490 }
491
492 go_combos();
493
494 int32_t combo=startCombo-1;
495 for(int32_t row=0; row<numRows; row++)
496 {
497 for(int32_t col=0; col<numCols; col++)
498 {
499 int32_t tile=startTile+row*TILES_PER_ROW+col;
500 if(smartWrap)
501 // Add 4 per row, and another numRows*4 for every 4 columns
502 // (col&0xFC==col/4*4), and then the column %4
503 combo=startCombo+4*row+(col&0xFC)*numRows+col%4;
504 else
505 combo++;
506
507 combobuf[combo]=combobuf[startCombo];
508 combobuf[combo].set_tile(tile);
509 }
510 }
511
512 setup_combo_animations();
513 setup_combo_animations2();
514 }
515
516 int32_t d_combo_proc(int32_t msg,DIALOG *d,int32_t c);
517
518 static bool nogotiles = false;
519 static bool nogocombos = false;
520
521 void go_tiles()
522 {
523 if(nogotiles) return;
524 last_tile_move_list = nullopt;
525 for(int32_t i=0; i<NEWMAXTILES; ++i)
526 {
527 newundotilebuf[i].format=newtilebuf[i].format;
528
529 if(newundotilebuf[i].data!=NULL)
530 {
531 free(newundotilebuf[i].data);
532 }
533
534 newundotilebuf[i].data=(byte *)malloc(tilesize(newundotilebuf[i].format));
535
536 if(newundotilebuf[i].data==NULL)
537 {
538 Z_error_fatal("Unable to initialize undo tile #%ld.\n", i);
539 }
540
541 memcpy(newundotilebuf[i].data,newtilebuf[i].data,tilesize(newundotilebuf[i].format));
542 }
543 }
544
545 void go_slide_tiles(int32_t columns, int32_t rows, int32_t top, int32_t left)
546 {
547 for(int32_t c=0; c<columns; c++)
548 {
549 for(int32_t r=0; r<rows; r++)
550 {
551 int32_t t=((top+r)*TILES_PER_ROW)+left+c;
552 newundotilebuf[t].format=newtilebuf[t].format;
553
554 if(newundotilebuf[t].data!=NULL)
555 {
556 free(newundotilebuf[t].data);
557 }
558
559 newundotilebuf[t].data=(byte *)malloc(tilesize(newundotilebuf[t].format));
560
561 if(newundotilebuf[t].data==NULL)
562 {
563 Z_error_fatal("Unable to initialize undo tile #%ld.\n", t);
564 }
565
566 memcpy(newundotilebuf[t].data,newtilebuf[t].data,tilesize(newundotilebuf[t].format));
567 }
568 }
569 }
570
571 void comeback_tiles()
572 {
573 if(last_tile_move_list)
574 {
575 last_tile_move_list->undo();
576 last_tile_move_list = nullopt;
577 }
578 for(dword i=0; i<NEWMAXTILES; ++i)
579 {
580 if(newtilebuf[i].format != newundotilebuf[i].format || !newtilebuf[i].data)
581 {
582 newtilebuf[i].format = newundotilebuf[i].format;
583
584 if(newtilebuf[i].data!=NULL)
585 free(newtilebuf[i].data);
586 newtilebuf[i].data=(byte *)malloc(tilesize(newtilebuf[i].format));
587 if(newtilebuf[i].data==NULL)
588 Z_error_fatal("Unable to initialize tile #%ld.\n", i);
589 }
590
591 memcpy(newtilebuf[i].data,newundotilebuf[i].data,tilesize(newtilebuf[i].format));
592 }
593
594 register_blank_tiles();
595 register_used_tiles();
596 }
597
598 void go_combos()
599 {
600 if(nogocombos) return;
601 last_combo_move_list = nullopt;
602
603 undocombobuf = combobuf;
604 }
605
606 void comeback_combos()
607 {
608 if(last_combo_move_list)
609 {
610 last_combo_move_list->undo();
611 last_combo_move_list = nullopt;
612 }
613
614 combobuf = undocombobuf;
615 }
616
617 void little_x(BITMAP *dest, int32_t x, int32_t y, int32_t c, int32_t s)
618 {
619 line(dest,x,y,x+s,y+s,c);
620 line(dest,x+s,y,x,y+s,c);
621 }
622 void little_x(BITMAP *dest, int32_t x, int32_t y, int32_t c, int32_t w, int32_t h)
623 {
624 line(dest,x,y,x+w,y+h,c);
625 line(dest,x+w,y,x,y+h,c);
626 }
627
628 enum {gm_light, gm_dark, gm_max};
629 int32_t gridmode=gm_light;
630
631 bool has_selection()
632 {
633 for(int32_t i=1; i<17; ++i)
634 {
635 for(int32_t j=1; j<17; ++j)
636 {
637 if(selection_grid[i][j])
638 {
639 return true;
640 }
641 }
642 }
643
644 return false;
645 }
646
647 void draw_selection_outline(BITMAP *dest, int32_t x, int32_t y, int32_t scale2)
648 {
649 drawing_mode(DRAW_MODE_COPY_PATTERN, selection_pattern, selection_anchor>>3, 0);
650
651 for(int32_t i=1; i<18; ++i)
652 {
653 for(int32_t j=1; j<18; ++j)
654 {
655 // zoomtile16(screen2,tile,79,31,cs,flip,8);
656 if(selection_grid[i-1][j]!=selection_grid[i][j])
657 {
658 vline(dest, x+((i-1)*scale2), y+((j-1)*scale2), y+(j*scale2), 255);
659 }
660
661 if(selection_grid[i][j-1]!=selection_grid[i][j])
662 {
663 hline(dest, x+((i-1)*scale2), y+((j-1)*scale2), x+(i*scale2), 255);
664 }
665 }
666 }
667
668 drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
669 // selection_anchor=(selection_anchor+1)%64;
670 }
671
672 bool is_selecting()
673 {
674 return (selecting_x1>-1&&selecting_x2>-1&&selecting_y1>-1&&selecting_y2>-1);
675 }
676
677 void draw_selecting_outline(BITMAP *dest, int32_t x, int32_t y, int32_t scale2)
678 {
679 int32_t x1=zc_min(selecting_x1,selecting_x2);
680 int32_t x2=zc_max(selecting_x1,selecting_x2);
681 int32_t y1=zc_min(selecting_y1,selecting_y2);
682 int32_t y2=zc_max(selecting_y1,selecting_y2);
683
684 // rect(dest, x+(x1*scale2), y+(y1*scale2), x+((x2+1)*scale2), y+((y2+1)*scale2), 255);
685 for(int32_t i=1; i<18; ++i)
686 {
687 for(int32_t j=1; j<18; ++j)
688 {
689 drawing_mode(DRAW_MODE_COPY_PATTERN, selecting_pattern, selection_anchor>>3, 0);
690
691 if(((j>=y1+1)&&(j<=y2+1))&&((i==x1+1)||(i==x2+2)))
692 {
693 if(selection_grid[i-1][j]!=selection_grid[i][j])
694 {
695 drawing_mode(DRAW_MODE_COPY_PATTERN, intersection_pattern, selection_anchor>>3, 0);
696 }
697
698 vline(dest, x+((i-1)*scale2), y+((j-1)*scale2), y+(j*scale2), 255);
699 }
700
701 if(((i>=x1+1)&&(i<=x2+1))&&((j==y1+1)||(j==y2+2)))
702 {
703 if(selection_grid[i][j-1]!=selection_grid[i][j])
704 {
705 drawing_mode(DRAW_MODE_COPY_PATTERN, intersection_pattern, selection_anchor>>3, 0);
706 }
707
708 hline(dest, x+((i-1)*scale2), y+((j-1)*scale2), x+(i*scale2), 255);
709 }
710 }
711 }
712
713 drawing_mode(DRAW_MODE_SOLID, NULL, 0, 0);
714 // selection_anchor=(selection_anchor+1)%64;
715 }
716
717 void unfloat_selection();
718 bool floating_sel = false;
719 byte floatsel[256];
720 byte undofloatsel[256];
721 bool undo_is_floatsel = false;
722
723
724 void add_color_to_selection(int32_t color)
725 {
726 unfloat_selection();
727 for(int32_t i=1; i<17; ++i)
728 {
729 for(int32_t j=1; j<17; ++j)
730 {
731 if(unpackbuf[((j-1)<<4)+(i-1)]==color)
732 {
733 selection_grid[i][j]=1;
734 }
735 }
736 }
737 }
738
739 void remove_color_from_selection(int32_t color)
740 {
741 unfloat_selection();
742 for(int32_t i=1; i<17; ++i)
743 {
744 for(int32_t j=1; j<17; ++j)
745 {
746 if(unpackbuf[((j-1)<<4)+(i-1)]==color)
747 {
748 selection_grid[i][j]=0;
749 }
750 }
751 }
752 }
753
754 void intersect_color_with_selection(int32_t color)
755 {
756 unfloat_selection();
757 for(int32_t i=1; i<17; ++i)
758 {
759 for(int32_t j=1; j<17; ++j)
760 {
761 if((unpackbuf[((j-1)<<4)+(i-1)]==color)&&(selection_grid[i][j]==1))
762 {
763 selection_grid[i][j]=1;
764 }
765 else
766 {
767 selection_grid[i][j]=0;
768 }
769 }
770 }
771 }
772
773 bool is_in_selection(int32_t x, int32_t y)
774 {
775 x %= 16; y %= 16;
776 if(x < 0) x = (16 - abs(x));
777 if(y < 0) y = (16 - abs(y));
778 return (!has_selection()||(selection_grid[x+1][y+1]!=0));
779 }
780
781 void zoomtile16(BITMAP *dest,int32_t tile,int32_t x,int32_t y,int32_t cset,int32_t flip,int32_t m)
782 {
783 // rectfill(dest,x,y,x+(16*m),y+(16*m),gridmode==gm_light?jwin_pal[jcMEDLT]:jwin_pal[jcDARK]);
784 int gridcol = gridmode==gm_light?vc(7):vc(8);
785
786 cset <<= 4;
787 if(newtilebuf[tile].format>tf4Bit)
788 cset=0;
789
790 int g = hide_grid ? 1 : 0;
791 byte transp_col = (bgmode == BGMODE_TRANSP ? jwin_pal[jcBOX] : 0+cset);
792 rectfill(dest,x,y,x+(16*m)+g,y+(16*m)+g,transp_col);
793
794 unpack_tile(newtilebuf, tile, 0, false);
795 byte *si = unpackbuf;
796 for(int32_t cy=0; cy<16; cy++)
797 {
798 for(int32_t cx=0; cx<16; cx++)
799 {
800 byte col = (floating_sel && floatsel[cx+(cy<<4)]) ? floatsel[cx+(cy<<4)] : *si;
801 int32_t dx = ((flip&1)?15-cx:cx)*m;
802 int32_t dy = ((flip&2)?15-cy:cy)*m;
803 if(col)
804 rectfill(dest,x+dx,y+dy,x+dx+m-1,y+dy+m-1,col+cset);
805
806 if(!col && xmode == XMODE_X)
807 little_x(dest,x+dx+m/4,y+dy+m/4,invcol,m/2);
808
809 ++si;
810 }
811 }
812
813 if(!hide_grid)
814 {
815 for(int cx = 0; cx <= 16; ++cx)
816 vline(dest,x+(cx*m),y,y+(16*m)-1,gridcol);
817 for(int cy = 0; cy <= 16; ++cy)
818 hline(dest,x,y+(cy*m),x+(16*m)-1,gridcol);
819 }
820
821 if(show_quartgrid)
822 {
823 int offs = (8*m);
824 const int RAD = 3;
825 rectfill(dest,x+offs-RAD,y,x+offs+RAD,y+(16*m),gridcol);
826 rectfill(dest,x,y+offs-RAD,x+(16*m),y+offs+RAD,gridcol);
827 }
828
829 if(has_selection()||is_selecting())
830 {
831 selection_anchor=(selection_anchor+1)%64;
832
833 if(has_selection()||is_selecting())
834 draw_selection_outline(dest, x, y, m);
835
836 if(is_selecting())
837 draw_selecting_outline(dest, x, y, m);
838 }
839 }
840
841 void draw_text_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,const char *text,int32_t bg,int32_t fg,int32_t flags,bool jwin)
842 {
843 if(!jwin)
844 {
845 if(flags&D_SELECTED)
846 {
847 zc_swap(fg,bg);
848 }
849
850 rect(dest,x+1,y+1,x+w-1,y+h-1,fg);
851 rectfill(dest,x+1,y+1,x+w-3,y+h-3,bg);
852 rect(dest,x,y,x+w-2,y+h-2,fg);
853 textout_centre_ex(dest,font,text,(x+x+w)>>1,((y+y+h)>>1)-4,fg,-1);
854 }
855 else
856 {
857 jwin_draw_text_button(dest, x, y, w, h, text, flags, true);
858 }
859 }
860
861 void draw_icon_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int icon,int32_t bg,int32_t fg,int32_t flags,bool jwin)
862 {
863 if(!jwin)
864 {
865 if(flags&D_SELECTED)
866 {
867 zc_swap(fg,bg);
868 }
869
870 rect(dest,x+1,y+1,x+w-1,y+h-1,fg);
871 rectfill(dest,x+1,y+1,x+w-3,y+h-3,bg);
872 rect(dest,x,y,x+w-2,y+h-2,fg);
873 jwin_draw_icon(dest,x+w/2,y+h/2,fg,icon,icon_proportion(icon,w,h),true);
874 }
875 else
876 {
877 jwin_draw_icon_button(dest, x, y, w, h, icon, flags, true);
878 }
879 }
880
881 void draw_layer_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,const char *text,int32_t flags)
882 {
883 if(flags&D_SELECTED)
884 {
885 rect(dest, x, y, x+w-1, y+h-1, jwin_pal[jcDARK]);
886 ++x;
887 ++y;
888 --w;
889 --h;
890 }
891 rectfill(dest,x+1,y+1,x+w-3,y+h-3,jwin_pal[(flags&D_SELECTED ? jcMEDDARK : jcBOX)]);
892 jwin_draw_frame(dest, x, y, w, h, (flags&D_SELECTED ? FR_DARK : FR_BOX));
893
894 //Forcibly fit the text within the button
895 char buf[512] = {0};
896 strcpy(buf, text);
897
898 bool dis = (flags&D_DISABLED);
899 auto hei = text_height(font);
900 auto len = text_length(font,buf);
901 auto borderwid = 8;
902 if(len > w - borderwid + (dis ? 1 : 0))
903 {
904 auto ind = strlen(buf) - 1;
905 auto dotcount = 0;
906 while(len > w - borderwid + (dis ? 1 : 0))
907 {
908 if(dotcount >= 2)
909 buf[ind+2] = 0;
910 else ++dotcount;
911 buf[ind--] = '.';
912 len = text_length(font,buf);
913 }
914 }
915 if(dis)
916 {
917 ++len; ++hei;
918 }
919 BITMAP* tmp = create_bitmap_ex(8,len,hei);
920 clear_bitmap(tmp);
921 if(dis)
922 {
923 textout_ex(tmp,font,buf,1,1,jwin_pal[jcLIGHT],-1);
924 textout_ex(tmp,font,buf,0,0,jwin_pal[jcDISABLED_FG],-1);
925 }
926 else
927 textout_ex(tmp,font,buf,0,0,jwin_pal[jcBOXFG],-1);
928 auto tx = x+((w-len)/2);
929 auto ty = y+((h-hei)/2);
930 if(len > w-borderwid)
931 {
932 tx = x+borderwid/2;
933 len = w-borderwid;
934 }
935 if(hei > h-borderwid)
936 {
937 ty = y+borderwid/2;
938 hei = h-borderwid;
939 }
940 masked_blit(tmp,dest, 0,0, tx,ty, len, hei);
941 destroy_bitmap(tmp);
942 }
943
944 bool do_layer_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text, int32_t flags, bool toggleflag)
945 {
946 bool over=false;
947
948 while(gui_mouse_b())
949 {
950 //vsync();
951 if(mouse_in_rect(x,y,w,h))
952 {
953 if(!over)
954 {
955 vsync();
956 draw_layer_button(screen, x, y, w, h, text, flags^D_SELECTED);
957 over=true;
958
959 update_hw_screen();
960 }
961 }
962 else
963 {
964 if(over)
965 {
966 vsync();
967 draw_layer_button(screen, x, y, w, h, text, flags);
968 over=false;
969
970 update_hw_screen();
971 }
972 }
973 //rest(1);
974 }
975
976 if(over)
977 {
978 vsync();
979 draw_layer_button(screen, x, y, w, h, text, toggleflag ? flags^D_SELECTED : flags);
980
981 update_hw_screen();
982 }
983
984 return over;
985 }
986
987 bool do_text_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text,int32_t bg,int32_t fg,bool jwin, bool sel)
988 {
989 bool over=false;
990
991 while(gui_mouse_b())
992 {
993 custom_vsync();
994
995 if(isinRect(gui_mouse_x(),gui_mouse_y(),x,y,x+w-1,y+h-1))
996 {
997 if(!over)
998 {
999 draw_text_button(screen,x,y,w,h,text,fg,bg,sel?0:D_SELECTED,jwin);
1000 over=true;
1001 }
1002 }
1003 else
1004 {
1005 if(over)
1006 {
1007 draw_text_button(screen,x,y,w,h,text,fg,bg,sel?D_SELECTED:0,jwin);
1008 over=false;
1009 }
1010 }
1011 }
1012
1013 if(over)
1014 {
1015 custom_vsync();
1016 draw_text_button(screen,x,y,w,h,text,fg,bg,sel?0:D_SELECTED,jwin);
1017 }
1018
1019 return over;
1020 }
1021
1022 void draw_graphics_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,BITMAP *bmp,BITMAP *bmp2,int32_t bg,int32_t fg,int32_t flags,bool jwin,bool overlay)
1023 {
1024 if(!jwin)
1025 {
1026 if(flags&D_SELECTED)
1027 {
1028 zc_swap(fg,bg);
1029 }
1030
1031 rect(dest,x+1,y+1,x+w-1,y+h-1,fg);
1032 rectfill(dest,x+1,y+1,x+w-3,y+h-3,bg);
1033 rect(dest,x,y,x+w-2,y+h-2,fg);
1034 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1035
1036 if(overlay)
1037 {
1038 masked_blit(bmp, dest, 0, 0, x+w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1039 }
1040 else
1041 {
1042 blit(bmp, dest, 0, 0, x+w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1043 }
1044 }
1045 else
1046 {
1047 jwin_draw_graphics_button(dest, x, y, w, h, bmp, bmp2, flags, false, overlay);
1048 }
1049 }
1050
1051 bool do_graphics_button(int32_t x,int32_t y,int32_t w,int32_t h,BITMAP *bmp,BITMAP *bmp2,int32_t bg,int32_t fg,bool jwin,bool overlay)
1052 {
1053 bool over=false;
1054
1055 while(gui_mouse_b())
1056 {
1057 custom_vsync();
1058
1059 if(isinRect(gui_mouse_x(),gui_mouse_y(),x,y,x+w-1,y+h-1))
1060 {
1061 if(!over)
1062 {
1063 draw_graphics_button(screen,x,y,w,h,bmp,bmp2,fg,bg,D_SELECTED,jwin,overlay);
1064 over=true;
1065 }
1066 }
1067 else
1068 {
1069 if(over)
1070 {
1071 draw_graphics_button(screen,x,y,w,h,bmp,bmp2,fg,bg,0,jwin,overlay);
1072 over=false;
1073 }
1074 }
1075 }
1076
1077 return over;
1078 }
1079
1080 bool do_graphics_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,BITMAP *bmp,BITMAP *bmp2,int32_t bg,int32_t fg,bool jwin,bool overlay)
1081 {
1082 bool over=false;
1083
1084 while(gui_mouse_b())
1085 {
1086 custom_vsync();
1087
1088 if(isinRect(gui_mouse_x(),gui_mouse_y(),x,y,x+w-1,y+h-1))
1089 {
1090 if(!over)
1091 {
1092 draw_graphics_button(screen,x,y,w,h,bmp,bmp2,fg,bg,D_SELECTED,jwin,overlay);
1093 over=true;
1094 }
1095 }
1096 else
1097 {
1098 if(over)
1099 {
1100 draw_graphics_button(screen,x,y,w,h,bmp,bmp2,fg,bg,0,jwin,overlay);
1101 over=false;
1102 }
1103 }
1104 }
1105
1106 if(over)
1107 {
1108 custom_vsync();
1109 draw_graphics_button(screen,x,y,w,h,bmp,bmp2,fg,bg,0,jwin,overlay);
1110 }
1111
1112 return over;
1113 }
1114 // circle(BITMAP *bmp, int32_t x, int32_t y, int32_t radius, int32_t color);
1115 // circlefill(BITMAP *bmp, int32_t x, int32_t y, int32_t radius, int32_t color);
1116
1117 void draw_layerradio(BITMAP *dest,int32_t x,int32_t y,int32_t bg,int32_t fg, int32_t value)
1118 {
1119 //these are here to bypass compiler warnings about unused arguments
1120 bg=bg;
1121 fg=fg;
1122
1123 int32_t r, center;
1124
1125 for(int32_t k=0; k<7; k++)
1126 {
1127 if((k==0)||(Map.CurrScr()->layermap[k-1]))
1128 {
1129 // circle(dest, x+(k*25)+4, y+4, 4, fg);
1130 // circlefill(dest, x+(k*25)+4, y+4, 2, (value==k)?fg:bg);
1131 //*
1132 r = 9/2;
1133
1134 center = x+(k*25)+r;
1135 rectfill(dest, x+(k*25), y, x+(k*25)+9-1, y+9-1, jwin_pal[jcBOX]);
1136
1137 circlefill(dest, center, y+r, r, jwin_pal[jcLIGHT]);
1138 arc(dest, center, y+r, itofix(32), itofix(160), r, jwin_pal[jcMEDDARK]);
1139 circlefill(dest, center, y+r, r-1, jwin_pal[jcMEDLT]);
1140 arc(dest, center, y+r, itofix(32), itofix(160), r-1, jwin_pal[jcDARK]);
1141 circlefill(dest, center, y+r, r-2, jwin_pal[jcLIGHT]);
1142
1143 if(value==k)
1144 {
1145 circlefill(dest, center, y+r, r-3, jwin_pal[jcDARK]);
1146 }
1147
1148 //*/
1149 }
1150 }
1151 }
1152
1153 void do_layerradio(BITMAP *dest,int32_t x,int32_t y,int32_t bg,int32_t fg,int32_t &value)
1154 {
1155 while(gui_mouse_b())
1156 {
1157 custom_vsync();
1158
1159 for(int32_t k=0; k<7; k++)
1160 {
1161 if((k==0)||(Map.CurrScr()->layermap[k-1]))
1162 {
1163 //if on radio button
1164 if(isinRect(gui_mouse_x(),gui_mouse_y(),x+(k*25),y,x+(k*25)+8,y+8))
1165 {
1166 value=k;
1167 draw_layerradio(dest,x,y,bg,fg,value);
1168 refresh(rMENU);
1169 }
1170 }
1171 }
1172 }
1173 }
1174
1175 //*************** tile flood fill stuff **************
1176
1177 byte tf_c;
1178 byte tf_u;
1179
1180 void tile_floodfill_rec(int32_t x,int32_t y)
1181 {
1182 if(is_in_selection(x,y))
1183 {
1184 while(x>0 && (unpackbuf[(y<<4)+x-1] == tf_u))
1185 --x;
1186
1187 while(x<=15 && (unpackbuf[(y<<4)+x] == tf_u))
1188 {
1189 if(is_in_selection(x,y))
1190 {
1191 unpackbuf[(y<<4)+x] = tf_c;
1192 }
1193
1194 if(y>0 && (unpackbuf[((y-1)<<4)+x] == tf_u))
1195 tile_floodfill_rec(x,y-1);
1196
1197 if(y<15 && (unpackbuf[((y+1)<<4)+x] == tf_u))
1198 tile_floodfill_rec(x,y+1);
1199
1200 ++x;
1201 }
1202 }
1203 }
1204
1205 void tile_floodfill(int32_t tile,int32_t x,int32_t y,byte c)
1206 {
1207 if(is_in_selection(x,y))
1208 {
1209 if(floating_sel)
1210 {
1211 memcpy(unpackbuf, floatsel, 256);
1212 }
1213 else unpack_tile(newtilebuf, tile, 0, false);
1214 tf_c = c;
1215 tf_u = unpackbuf[(y<<4)+x];
1216
1217 if(tf_u != tf_c)
1218 tile_floodfill_rec(x,y);
1219 if(floating_sel)
1220 {
1221 memcpy(floatsel, unpackbuf, 256);
1222 }
1223 else pack_tile(newtilebuf,unpackbuf,tile);
1224 }
1225 }
1226
1227 //***************** tile editor stuff *****************
1228 12 size_and_pos ok_button(302,562,71,21);
1229 12 size_and_pos cancel_button(376,562,71,21);
1230 12 size_and_pos edit_button(550,562,86,21);
1231 12 size_and_pos hlcbox(742,392,16,16);
1232 12 size_and_pos hov_prev(742,338,50,50);
1233 12 size_and_pos cpalette_4(648,416,4,4,64,64);
1234 12 size_and_pos cpalette_8(648,416,16,14,16,18);
1235 12 size_and_pos fg_prev(648,316,50,50);
1236 12 size_and_pos bg_prev(648+30,316+30,50,50);
1237 12 size_and_pos zoomtile(124,32,16,16,32,32);
1238 12 size_and_pos prev_til_1(648,31,96,96);
1239 12 size_and_pos prev_til_2(752,31,96,96);
1240 12 size_and_pos prev_til_3(648,135,96,96);
1241 12 size_and_pos prev_til_4(752,135,96,96);
1242 12 size_and_pos ref_til(14,189,96,96);
1243 12 size_and_pos status_info(648,308-(4*8),1,4,1,8);
1244 12 size_and_pos hover_info(742,338-(3*8),1,3,1,8);
1245 12 size_and_pos color_info(4,294,1,1,116,8);
1246 12 size_and_pos color_info_btn(24,294,96,21);
1247 12 size_and_pos tool_btns(22,29,2,4,39,39);
1248 12 size_and_pos x_btn(890,5,15,13);
1249 12 size_and_pos info_btn(872,5,15,13);
1250 12 size_and_pos hidegrid_cbox(124,552,16,16);
1251 12 size_and_pos quartgrid_cbox(124,572,16,16);
1252 12 size_and_pos reflbtn_grid(124,610,2,3,71,21);
1253 12 size_and_pos xmodebtn_grid(300,610,1,2,90,21);
1254 12 size_and_pos bgmodebtn_grid(390,610,1,2,90,21);
1255
1256 int32_t c1=1;
1257 int32_t c2=0;
1258 int32_t floating_tile = -1;
1259 int32_t tool = t_pen;
1260 int32_t old_tool = -1;
1261 int32_t tool_cur = -1;
1262 int32_t select_mode = 0;
1263 int32_t drawing=0;
1264 int32_t reftile = 0;
1265
1266 bool qgrid_tool(int tool)
1267 {
1268 switch(tool)
1269 {
1270 case t_pen:
1271 case t_fill:
1272 case t_recolor:
1273 case t_wand:
1274 return true;
1275 }
1276 return false;
1277 }
1278
1279 void set_tool_sprite(int tool, int type)
1280 {
1281 int spr = ZQM_NORMAL;
1282 switch(tool)
1283 {
1284 case t_pen: spr = ZQM_SWORD; break;
1285 case t_fill: spr = ZQM_POTION; break;
1286 case t_recolor: spr = ZQM_WAND; break;
1287 case t_eyedropper: spr = ZQM_LENS; break;
1288 case t_move: spr = ZQM_GLOVE_OPEN+type; break;
1289 case t_select: spr = ZQM_HOOK_PLAIN+type; break;
1290 case t_wand: spr = ZQM_SEL_WAND_PLAIN+type; break;
1291 }
1292 MouseSprite::set(spr);
1293 }
1294 void update_tool_cursor()
1295 {
1296 int32_t temp_mouse_x=gui_mouse_x();
1297 int32_t temp_mouse_y=gui_mouse_y();
1298
1299 int32_t type=0;
1300
1301 if(has_selection())
1302 {
1303 switch(tool)
1304 {
1305 case t_select:
1306 case t_wand:
1307 type+=select_mode;
1308 break;
1309 }
1310 }
1311
1312 if(isinRect(temp_mouse_x,temp_mouse_y,zoomtile.x,zoomtile.y-(tool==t_fill ? (14) : 0),zoomtile.x+(zoomtile.w*zoomtile.xscale)-2,zoomtile.y+(zoomtile.h*zoomtile.yscale)-2-(tool==t_fill ? (14) : 0))) //inside the zoomed tile window
1313 {
1314 if(tool_cur==-1)
1315 set_tool_sprite(tool,type);
1316
1317 tool_cur=tool;
1318 }
1319 else if(tool_cur != -1)
1320 {
1321 MouseSprite::set(ZQM_NORMAL);
1322 tool_cur = -1;
1323 }
1324 }
1325
1326 void draw_edit_scr(int32_t tile,int32_t flip,int32_t cs,byte *oldtile,bool create_tbar)
1327 {
1328 PALETTE tpal;
1329 static BITMAP *tbar = create_bitmap_ex(8,zq_screen_w-6, 18);
1330 static BITMAP *preview_bmp = create_bitmap_ex(8, 64, 64);
1331 jwin_draw_win(screen2, 0, 0, zq_screen_w, zq_screen_h, FR_WIN);
1332
1333 if(!create_tbar)
1334 {
1335 blit(tbar, screen2, 0, 0, 3, 3, zq_screen_w-6, 18);
1336 }
1337 else
1338 {
1339 jwin_draw_titlebar(tbar, 0, 0, zq_screen_w-6, 18, "", true, true);
1340 blit(tbar, screen2, 0, 0, 3, 3, zq_screen_w-6, 18);
1341 }
1342
1343 textprintf_ex(screen2,get_zc_font(font_lfont),5,5,jwin_pal[jcTITLEFG],-1,"Tile Editor (%d)",tile);
1344
1345 clear_to_color(preview_bmp, 0);
1346
1347 zc_swap(oldtile,newtilebuf[tile].data); //Put oldtile in the tile buffer
1348 jwin_draw_win(screen2, prev_til_1.x-2,prev_til_1.y-2, prev_til_1.w+4, prev_til_1.h+4, FR_DEEP);
1349 puttile16(preview_bmp,tile,0,0,cs,flip);
1350 stretch_blit(preview_bmp, screen2, 0, 0, 16, 16, prev_til_1.x, prev_til_1.y, prev_til_1.w, prev_til_1.h);
1351
1352 clear_to_color(preview_bmp, 0);
1353 jwin_draw_win(screen2, prev_til_2.x-2,prev_til_2.y-2, prev_til_2.w+4, prev_til_2.h+4, FR_DEEP);
1354 overtile16(preview_bmp,tile,0,0,cs,flip);
1355 masked_stretch_blit(preview_bmp, screen2, 0, 0, 16, 16, prev_til_2.x, prev_til_2.y, prev_til_2.w, prev_til_2.h);
1356 zc_swap(oldtile,newtilebuf[tile].data); //Swap the real tile back to the buffer
1357
1358 unpack_tile(newtilebuf, tile, 0, true);
1359 if(floating_sel)
1360 for(auto q = 0; q < 256; ++q)
1361 if(floatsel[q])
1362 unpackbuf[q] = floatsel[q];
1363 byte tmptile[256];
1364 byte *tmpptr = tmptile;
1365 zc_swap(tmpptr,newtilebuf[tile].data); //Put temp data in the tile buffer
1366 pack_tile(newtilebuf,unpackbuf,tile);
1367 clear_to_color(preview_bmp, 0);
1368
1369 jwin_draw_win(screen2, prev_til_3.x-2,prev_til_3.y-2, prev_til_3.w+4, prev_til_3.h+4, FR_DEEP);
1370 puttile16(preview_bmp,tile,0,0,cs,flip);
1371 stretch_blit(preview_bmp, screen2, 0, 0, 16, 16, prev_til_3.x, prev_til_3.y, prev_til_3.w, prev_til_3.h);
1372
1373 clear_to_color(preview_bmp, 0);
1374 jwin_draw_win(screen2, prev_til_4.x-2,prev_til_4.y-2, prev_til_4.w+4, prev_til_4.h+4, FR_DEEP);
1375 overtile16(preview_bmp,tile,0,0,cs,flip);
1376 masked_stretch_blit(preview_bmp, screen2, 0, 0, 16, 16, prev_til_4.x, prev_til_4.y, prev_til_4.w, prev_til_4.h);
1377
1378 if(reftile > 0)
1379 {
1380 clear_to_color(preview_bmp, 0);
1381 jwin_draw_win(screen2, ref_til.x-2,ref_til.y-2, ref_til.w+4, ref_til.h+4, FR_DEEP);
1382 overtile16(preview_bmp,reftile,0,0,cs,flip);
1383 masked_stretch_blit(preview_bmp, screen2, 0, 0, 16, 16, ref_til.x, ref_til.y, ref_til.w, ref_til.h);
1384 }
1385
1386 //Color info
1387 {
1388 color_info.h = 1;
1389 if(showcolortip)
1390 {
1391 auto fh = color_info.yscale = text_height(font);
1392 int ty = color_info.y;
1393 if(reftile <= 0)
1394 ty -= ref_til.h + 8;
1395 int y = ty;
1396 int rx = color_info.x+color_info.xscale;
1397 gui_textout_ln(screen2,font,(unsigned char*)"Colors:",
1398 rx,y,jwin_pal[jcBOXFG],jwin_pal[jcBOX],2);
1399 auto str = get_tile_colornames(tile,cs);
1400 size_t pos = 0;
1401 char buf[512] = {0};
1402 char cbuf[16] = {0};
1403 while(pos < str.size())
1404 {
1405 y += fh;
1406 if(y+fh > zq_screen_h)
1407 break; //Out of space!
1408 auto endpos = str.find_first_of('\n',pos);
1409
1410 if(endpos == std::string::npos)
1411 {
1412 strcpy(buf,str.substr(pos).c_str());
1413 pos = str.size();
1414 }
1415 else
1416 {
1417 strcpy(buf,str.substr(pos,endpos-pos+1).c_str());
1418 pos = endpos+1;
1419 }
1420 //Ensure the name fits horizontally
1421 if(text_length(font,buf) > color_info.xscale)
1422 {
1423 size_t pos = 0;
1424 for(; buf[pos]; ++pos)
1425 {
1426 if(buf[pos] == ':')
1427 {
1428 strcpy(cbuf, buf+pos);
1429 buf[pos] = 0;
1430 break;
1431 }
1432 }
1433 size_t clen = text_length(font,cbuf);
1434 size_t dotlen = text_length(font,"..");
1435
1436 while(pos > 0 && (dotlen+clen+text_length(font,buf) > color_info.xscale))
1437 buf[--pos] = 0;
1438 while(buf[pos] == ' ')
1439 buf[pos] = 0;
1440 strcat(buf,"..");
1441 strcat(buf,cbuf);
1442 }
1443 gui_textout_ln(screen2,font,(unsigned char const*)buf,
1444 rx,y,jwin_pal[jcBOXFG],jwin_pal[jcBOX],2);
1445 ++color_info.h;
1446 }
1447 jwin_draw_frame(screen2,color_info.x-2,ty-2,(color_info.w*color_info.xscale)+4,(color_info.h*color_info.yscale)+4,FR_DEEP);
1448 }
1449 else
1450 {
1451 int ty = color_info_btn.y;
1452 if(reftile <= 0)
1453 ty -= ref_til.h + 8;
1454 draw_text_button(screen2,color_info_btn.x,ty,color_info_btn.w,color_info_btn.h,
1455 "Show Colors",vc(1),vc(14),0,true);
1456 }
1457 }
1458
1459 zc_swap(tmpptr,newtilebuf[tile].data); //Swap the real tile back to the buffer
1460
1461 jwin_draw_win(screen2, zoomtile.x-3, zoomtile.y-3, (zoomtile.w*zoomtile.xscale)+5, (zoomtile.h*zoomtile.yscale)+5, FR_DEEP);
1462 zoomtile16(screen2,tile,zoomtile.x-1,zoomtile.y-1,cs,flip,zoomtile.xscale);
1463
1464 if(floating_sel)
1465 textprintf_ex(screen2,font,status_info.x,status_info.y+0,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"Floating selection");
1466 textprintf_ex(screen2,font,status_info.x,status_info.y+(1*status_info.yscale),jwin_pal[jcBOXFG],jwin_pal[jcBOX],"tile: %d",tile);
1467 if(newtilebuf[tile].format==tf8Bit)
1468 textprintf_ex(screen2,font,status_info.x,status_info.y+(2*status_info.yscale),jwin_pal[jcBOXFG],jwin_pal[jcBOX],"8-bit");
1469 else
1470 textprintf_ex(screen2,font,status_info.x,status_info.y+(2*status_info.yscale),jwin_pal[jcBOXFG],jwin_pal[jcBOX],"cset: %d",cs);
1471
1472 PALETTE temppal;
1473
1474 //palette and mouse
1475 switch(newtilebuf[tile].format)
1476 {
1477 case tf4Bit:
1478 jwin_draw_win(screen2, cpalette_4.x-2, cpalette_4.y-2, (cpalette_4.xscale*cpalette_4.w)+4, (cpalette_4.yscale*cpalette_4.h)+4, FR_DEEP);
1479 get_palette(temppal);
1480
1481 for(int32_t i=0; i<cpalette_4.w*cpalette_4.h; i++)
1482 {
1483 size_and_pos const& s = cpalette_4.subsquare(i);
1484 rectfill(screen2,s.x,s.y,s.x+s.w-1,s.y+s.h-1,CSET(cs)+i);
1485 }
1486
1487 little_x(screen2,cpalette_4.x+1,cpalette_4.y+1,invcol,cpalette_4.xscale-5,cpalette_4.yscale-5);
1488 break;
1489
1490 case tf8Bit:
1491 jwin_draw_win(screen2, cpalette_8.x-2, cpalette_8.y-2, (cpalette_8.xscale*cpalette_8.w)+4, (cpalette_8.yscale*cpalette_8.h)+4, FR_DEEP);
1492
1493 for(int32_t i=0; i<cpalette_8.w*cpalette_8.h; ++i)
1494 {
1495 size_and_pos const& s = cpalette_8.subsquare(i);
1496 rectfill(screen2,s.x,s.y,s.x+s.w-1,s.y+s.h-1,i);
1497 }
1498
1499 little_x(screen2,cpalette_8.x+1,cpalette_8.y+1,invcol,cpalette_8.xscale-5,cpalette_8.yscale-5);
1500 break;
1501 }
1502
1503 rect(screen2, bg_prev.x, bg_prev.y, bg_prev.x+bg_prev.w-1, bg_prev.y+bg_prev.h-1, jwin_pal[jcTEXTFG]);
1504 rectfill(screen2, bg_prev.x+1, bg_prev.y+1, bg_prev.x+bg_prev.w-2, bg_prev.y+bg_prev.h-2, jwin_pal[jcTEXTBG]);
1505 rectfill(screen2, bg_prev.x+3, bg_prev.y+3, bg_prev.x+bg_prev.w-4, bg_prev.y+bg_prev.h-4, c2+((newtilebuf[tile].format==tf4Bit)?CSET(cs):0));
1506
1507 if(c2==0)
1508 {
1509 little_x(screen2, bg_prev.x+1, bg_prev.y+1, invcol, bg_prev.w-2, bg_prev.h-2);
1510 }
1511
1512 rect(screen2, fg_prev.x, fg_prev.y, fg_prev.x+fg_prev.w-1, fg_prev.y+fg_prev.h-1, jwin_pal[jcTEXTFG]);
1513 rectfill(screen2, fg_prev.x+1, fg_prev.y+1, fg_prev.x+fg_prev.w-2, fg_prev.y+fg_prev.h-2, jwin_pal[jcTEXTBG]);
1514 rectfill(screen2, fg_prev.x+3, fg_prev.y+3, fg_prev.x+fg_prev.w-4, fg_prev.y+fg_prev.h-4, c1+((newtilebuf[tile].format==tf4Bit)?CSET(cs):0));
1515
1516 if(c1==0)
1517 {
1518 little_x(screen2, fg_prev.x+1, fg_prev.y+1, invcol, fg_prev.w-2, fg_prev.h-2);
1519 }
1520
1521 draw_text_button(screen2,ok_button.x,ok_button.y,ok_button.w,ok_button.h,"OK",vc(1),vc(14),0,true);
1522 draw_text_button(screen2,cancel_button.x,cancel_button.y,cancel_button.w,cancel_button.h,"Cancel",vc(1),vc(14),0,true);
1523 draw_text_button(screen2,edit_button.x,edit_button.y,edit_button.w,edit_button.h,"Edit Pal",vc(1),vc(14),0,true);
1524 draw_checkbox(screen2,hlcbox.x, hlcbox.y, hlcbox.w, hlcbox.h, tthighlight);
1525 gui_textout_ln(screen2,font,(unsigned char*)"Highlight Hover",hlcbox.x+hlcbox.w+2,hlcbox.y+hlcbox.h/2-text_height(font)/2,jwin_pal[jcBOXFG],jwin_pal[jcBOX],0);
1526
1527 draw_checkbox(screen2,quartgrid_cbox.x, quartgrid_cbox.y, quartgrid_cbox.w, quartgrid_cbox.h, show_quartgrid);
1528 gui_textout_ln(screen2,font,(unsigned char*)"Quarter Grid",quartgrid_cbox.x+quartgrid_cbox.w+2,quartgrid_cbox.y+quartgrid_cbox.h/2-text_height(font)/2,jwin_pal[jcBOXFG],jwin_pal[jcBOX],0);
1529
1530 draw_checkbox(screen2,hidegrid_cbox.x, hidegrid_cbox.y, hidegrid_cbox.w, hidegrid_cbox.h, hide_grid);
1531 gui_textout_ln(screen2,font,(unsigned char*)"Hide Grid",hidegrid_cbox.x+hidegrid_cbox.w+2,hidegrid_cbox.y+hidegrid_cbox.h/2-text_height(font)/2,jwin_pal[jcBOXFG],jwin_pal[jcBOX],0);
1532
1533 bool qgrd = show_quartgrid && qgrid_tool(tool);
1534 gui_textout_ln(screen2,font,(unsigned char*)"Quarter-Grid Draw Modes", reflbtn_grid.x, reflbtn_grid.y-text_height(font)-4,jwin_pal[jcBOXFG],jwin_pal[jcBOX],qgrd?0:D_DISABLED);
1535 for(int q = 0; q < REFL_MAX; ++q)
1536 {
1537 auto& sqr = reflbtn_grid.subsquare(q);
1538 draw_text_button(screen2,sqr.x,sqr.y,sqr.w,sqr.h,reflbtn_names[q],vc(1),vc(14),qgrd ? ((refl_flags&(1<<q)) ? D_SELECTED : 0) : D_DISABLED,true);
1539 }
1540 gui_textout_ln(screen2,font,(unsigned char*)"Transparent Mode", xmodebtn_grid.x, xmodebtn_grid.y-text_height(font)-4,jwin_pal[jcBOXFG],jwin_pal[jcBOX],0);
1541 for(int q = 0; q < XMODE_MAX; ++q)
1542 {
1543 auto& sqr = xmodebtn_grid.subsquare(q);
1544 draw_text_button(screen2,sqr.x,sqr.y,sqr.w,sqr.h,xmodebtn_names[q],vc(1),vc(14),(xmode == q) ? D_SELECTED : 0,true);
1545 }
1546 for(int q = 0; q < BGMODE_MAX; ++q)
1547 {
1548 auto& sqr = bgmodebtn_grid.subsquare(q);
1549 draw_text_button(screen2,sqr.x,sqr.y,sqr.w,sqr.h,bgmodebtn_names[q],vc(1),vc(14),(bgmode == q) ? D_SELECTED : 0,true);
1550 }
1551
1552 //tool buttons
1553 for(int32_t toolbtn = 0; toolbtn < t_max; ++toolbtn)
1554 {
1555 auto bmp = toolbtn+MOUSE_BMP_SWORD;
1556 int col = toolbtn%tool_btns.w;
1557 int row = toolbtn/tool_btns.w;
1558
1559 jwin_draw_button(screen2,tool_btns.x+(col*tool_btns.xscale),tool_btns.y+(row*tool_btns.yscale),tool_btns.xscale,tool_btns.yscale,tool==toolbtn?2:0,0);
1560 masked_stretch_blit(mouse_bmp_1x[bmp][0],screen2,0,0,16,16,tool_btns.x+(col*tool_btns.xscale)+3+(tool==toolbtn?1:0),tool_btns.y+3+(row*tool_btns.yscale)+(tool==toolbtn?1:0),tool_btns.xscale-7,tool_btns.yscale-7);
1561 }
1562
1563 //coordinates
1564 {
1565 auto mx = gui_mouse_x();
1566 auto my = gui_mouse_y();
1567 int32_t ind = zoomtile.rectind(mx,my);
1568 int32_t temp_x=ind%zoomtile.w;
1569 int32_t temp_y=ind/zoomtile.w;
1570 int color = -1;
1571
1572 bool is8b = newtilebuf[tile].format > tf4Bit;
1573 if(ind > -1)
1574 {
1575 char xbuf[16];
1576 sprintf(xbuf, "x: %d", temp_x);
1577 textprintf_ex(screen2,font,status_info.x,status_info.y+(3*status_info.yscale),jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%s",xbuf);
1578 textprintf_ex(screen2,font,status_info.x+text_length(font,xbuf)+8,status_info.y+(3*status_info.yscale),jwin_pal[jcBOXFG],jwin_pal[jcBOX],"y: %d",temp_y);
1579 unpack_tile(newtilebuf, tile, 0, false);
1580 byte *si = unpackbuf;
1581 si+=ind;
1582 color = *si;
1583 }
1584 else if(fg_prev.rect(mx,my))
1585 color = c1;
1586 else if(bg_prev.rect(mx,my))
1587 color = c2;
1588 else color = (is8b ? cpalette_8 : cpalette_4).rectind(mx,my);
1589 if(color > -1)
1590 {
1591 get_palette(tpal);
1592 char separator = ' ';
1593 char buf[512] = {0};
1594
1595 int realcol = color+(is8b?0:CSET(cs));
1596 bool xcolor = (is8b ? realcol == 0 : (realcol%16)==0);
1597 auto& c = tpal[realcol];
1598
1599 if(tthighlight)
1600 {
1601 size_and_pos const& mainsqr = is8b ? cpalette_8 : cpalette_4;
1602 size_and_pos const& csqr = mainsqr.subsquare(color);
1603
1604 int hlcol = getHighlightColor(tpal[realcol]);
1605 int hlthick = 4;
1606 int extraborder = is8b ? 8 : 0;
1607 int borderthick = hlthick+extraborder;
1608
1609 if(is8b)
1610 {
1611 highlight_sqr(screen2, 0xED, csqr.x, mainsqr.y, csqr.w, mainsqr.h*mainsqr.yscale, hlthick); //column
1612 highlight_sqr(screen2, 0xED, mainsqr.x, csqr.y, mainsqr.w*mainsqr.xscale, csqr.h, hlthick); //row
1613 }
1614 highlight_sqr(screen2, 0xED, csqr.x-borderthick, csqr.y-borderthick, csqr.w+borderthick*2, csqr.h+borderthick*2, hlthick); //square hl
1615 rectfill(screen2, csqr.x-extraborder, csqr.y-extraborder, csqr.x+csqr.w-1+extraborder, csqr.y+csqr.h-1+extraborder, realcol); //square color
1616 if(xcolor)
1617 little_x(screen2, csqr.x-extraborder+4, csqr.y-extraborder+4, invcol, csqr.w+(extraborder*2)-8, csqr.h+(extraborder*2)-8); //transparent X
1618 highlight_sqr(screen2, hlcol, csqr.x-extraborder, csqr.y-extraborder, csqr.w+extraborder*2, csqr.h+extraborder*2, 1); //highlight border
1619 }
1620
1621 sprintf(buf, "%02d %02d %02d %c(0x%02X %d)",c.r,c.g,c.b,separator,realcol,color);
1622 gui_textout_ln(screen2,font,(unsigned char*)buf,hover_info.x,hover_info.y+(2*hover_info.yscale),jwin_pal[jcBOXFG],jwin_pal[jcBOX],0);
1623
1624 strcpy(buf, get_color_name(realcol, is8b).c_str());
1625 gui_textout_ln(screen2,font,(unsigned char*)buf,hover_info.x,hover_info.y+(1*hover_info.yscale),jwin_pal[jcBOXFG],jwin_pal[jcBOX],0);
1626
1627 sprintf(buf, "#%02X%02X%02X", tpal[realcol].r,tpal[realcol].g,tpal[realcol].b);
1628 gui_textout_ln(screen2,font,(unsigned char*)buf,hover_info.x,hover_info.y+(0),jwin_pal[jcBOXFG],jwin_pal[jcBOX],0);
1629
1630 rect(screen2, hov_prev.x, hov_prev.y, hov_prev.x+hov_prev.w-1, hov_prev.y+hov_prev.h-1, jwin_pal[jcTEXTFG]);
1631 rectfill(screen2, hov_prev.x+1, hov_prev.y+1, hov_prev.x+hov_prev.w-2, hov_prev.y+hov_prev.h-2, jwin_pal[jcTEXTBG]);
1632 rectfill(screen2, hov_prev.x+3, hov_prev.y+3, hov_prev.x+hov_prev.w-4, hov_prev.y+hov_prev.h-4, realcol);
1633 if(xcolor)
1634 little_x(screen2, hov_prev.x+1, hov_prev.y+1, invcol, hov_prev.w-2, hov_prev.h-2);
1635 }
1636 }
1637
1638 blit(screen2,screen,0,0,0,0,zq_screen_w,zq_screen_w);
1639 update_tool_cursor();
1640 }
1641
1642 void normalize(int32_t tile,int32_t tile2, bool rect_sel, int32_t flip)
1643 {
1644 unfloat_selection();
1645 if(tile>tile2)
1646 {
1647 zc_swap(tile, tile2);
1648 }
1649
1650 int32_t left=zc_min(TILECOL(tile), TILECOL(tile2));
1651 int32_t columns=zc_max(TILECOL(tile), TILECOL(tile2))-left+1;
1652
1653 int32_t start=tile;
1654 int32_t end=tile2;
1655
1656 // Might have top-right and bottom-left corners selected...
1657 if(rect_sel && TILECOL(tile)>TILECOL(tile2))
1658 {
1659 start=tile-(TILECOL(tile)-TILECOL(tile2));
1660 end=tile2+(TILECOL(tile)-TILECOL(tile2));
1661 }
1662
1663 for(int32_t temptile=start; temptile<=end; temptile++)
1664 {
1665 if(!rect_sel || ((TILECOL(temptile)>=left) && (TILECOL(temptile)<=left+columns-1)))
1666 {
1667 unpack_tile(newtilebuf, temptile, 0, true);
1668
1669 if(flip&1)
1670 {
1671 for(int32_t y=0; y<16; y++)
1672 {
1673 for(int32_t x=0; x<8; x++)
1674 {
1675 zc_swap(unpackbuf[(y<<4)+x],unpackbuf[(y<<4)+15-x]);
1676 }
1677 }
1678 }
1679
1680 if(flip&2)
1681 {
1682 for(int32_t y=0; y<8; y++)
1683 {
1684 for(int32_t x=0; x<16; x++)
1685 {
1686 zc_swap(unpackbuf[(y<<4)+x],unpackbuf[((15-y)<<4)+x]);
1687 }
1688 }
1689 }
1690
1691 pack_tile(newtilebuf,unpackbuf,temptile);
1692 }
1693 }
1694 }
1695
1696 void rotate_tile(int32_t tile, bool backward)
1697 {
1698 unfloat_selection();
1699 unpack_tile(newtilebuf, tile, 0, true);
1700 byte tempunpackbuf[256];
1701 byte tempx, tempy;
1702
1703 for(tempx=0; tempx<16; tempx++)
1704 {
1705 for(tempy=0; tempy<16; tempy++)
1706 {
1707 if(!backward)
1708 {
1709 tempunpackbuf[(tempy<<4)+tempx]=unpackbuf[((15-tempx)<<4)+tempy];
1710 }
1711 else
1712 {
1713 tempunpackbuf[((15-tempx)<<4)+tempy]=unpackbuf[(tempy<<4)+tempx];
1714 }
1715 }
1716 }
1717
1718 pack_tile(newtilebuf,tempunpackbuf,tile);
1719 }
1720
1721 static int32_t undocount=128;
1722 byte undotile[256];
1723
1724 void wrap_tile(int32_t tile, int32_t vertical, int32_t horizontal, bool clear)
1725 {
1726 byte buf[256];
1727
1728 for(int32_t i=0; i<undocount; i++)
1729 {
1730 newtilebuf[tile].data[i]=undotile[i];
1731 }
1732
1733 if(!(horizontal||vertical))
1734 {
1735 return;
1736 }
1737
1738 unpack_tile(newtilebuf, tile, 0, true);
1739
1740 for(int32_t i=0; i<256; i++)
1741 {
1742 auto shift_ind = ((i+horizontal)&0x0F)|((i+(vertical*0x10))&0xF0);
1743 buf[shift_ind] = unpackbuf[i];
1744 }
1745
1746 if(clear)
1747 {
1748 for(int32_t r=0; r<abs(vertical); r++)
1749 {
1750 for(int32_t c=0; c<16; c++)
1751 {
1752 buf[(vertical>0?r:15-r)*16+c]=0;
1753 }
1754 }
1755
1756 for(int32_t r=0; r<16; r++)
1757 {
1758 for(int32_t c=0; c<abs(horizontal); c++)
1759 {
1760 buf[r*16+(horizontal>0?c:15-c)]=0;
1761 }
1762 }
1763 }
1764
1765 pack_tile(newtilebuf,buf,tile);
1766 }
1767
1768 void wrap_sel_tile(int32_t vertical, int32_t horizontal)
1769 {
1770 byte buf[256];
1771
1772 if(!(horizontal||vertical))
1773 {
1774 return;
1775 }
1776
1777 memset(buf,0,256);
1778
1779 for(int32_t i=0; i<256; i++)
1780 {
1781 if(is_in_selection(i%16,i/16))
1782 {
1783 auto shift_ind = ((i+horizontal)&0x0F)|((i+(vertical*0x10))&0xF0);
1784 buf[shift_ind] = floatsel[i];
1785 }
1786 }
1787
1788 memcpy(floatsel,buf,256);
1789 }
1790
1791 void float_selection(int32_t tile, bool clear)
1792 {
1793 if(floating_sel) return;
1794 floating_sel = true;
1795 floating_tile = tile;
1796
1797 unpack_tile(newtilebuf, tile, 0, true);
1798
1799 for(auto q = 0; q < 256; ++q)
1800 {
1801 if(is_in_selection(q%16,q/16))
1802 {
1803 floatsel[q] = unpackbuf[q];
1804 unpackbuf[q] = clear ? 0 : c2;
1805 }
1806 else floatsel[q] = 0;
1807 }
1808
1809 pack_tile(newtilebuf,unpackbuf,tile);
1810 }
1811
1812 void unfloat_selection()
1813 {
1814 if(!floating_sel) return;
1815 floating_sel = false;
1816
1817 unpack_tile(newtilebuf, floating_tile, 0, true);
1818
1819 for(auto q = 0; q < 256; ++q)
1820 {
1821 if(floatsel[q])
1822 {
1823 unpackbuf[q] = floatsel[q];
1824 }
1825 }
1826
1827 pack_tile(newtilebuf,unpackbuf,floating_tile);
1828 floating_tile = -1;
1829 }
1830
1831 void shift_tile_colors(int32_t tile, int32_t amount, bool ignore_transparent)
1832 {
1833 if(floating_sel)
1834 {
1835 for(auto q = 0; q < 256; ++q)
1836 {
1837 if(ignore_transparent && floatsel[q]==0)
1838 continue;
1839 floatsel[q]=wrap(floatsel[q]+amount, 0, newtilebuf[tile].format==tf8Bit ? 0xDF : 0xF);
1840 }
1841 return;
1842 }
1843
1844 byte buf[256];
1845 unpack_tile(newtilebuf, tile, 0, true);
1846
1847 for(int32_t i=0; i<256; i++)
1848 {
1849 buf[i]=unpackbuf[i];
1850
1851 if(!is_in_selection(i&0x0F, (i&0xF0)>>4))
1852 continue;
1853
1854 if(ignore_transparent)
1855 {
1856 if(buf[i]==0)
1857 continue;
1858
1859 buf[i]=wrap(buf[i]+amount, 1, newtilebuf[tile].format==tf8Bit ? 0xDF : 0xF);
1860 }
1861 else // Don't ignore transparent
1862 buf[i]=wrap(buf[i]+amount, 0, newtilebuf[tile].format==tf8Bit ? 0xDF : 0xF);
1863 }
1864
1865 pack_tile(newtilebuf,buf,tile);
1866 }
1867
1868 void clear_selection_grid()
1869 {
1870 unfloat_selection();
1871 for(int32_t x=0; x<18; ++x)
1872 {
1873 for(int32_t y=0; y<18; ++y)
1874 {
1875 selection_grid[x][y]=0;
1876 }
1877 }
1878 }
1879
1880 void invert_selection_grid()
1881 {
1882 unfloat_selection();
1883 for(int32_t x=1; x<17; ++x)
1884 {
1885 for(int32_t y=1; y<17; ++y)
1886 {
1887 selection_grid[x][y]=selection_grid[x][y]?0:1;
1888 }
1889 }
1890 }
1891
1892 void shift_selection_grid(int32_t xoffs, int32_t yoffs)
1893 {
1894 byte local_grid[16][16];
1895 memset(local_grid, 0, sizeof(local_grid));
1896 for(auto x = 0; x < 16; ++x)
1897 {
1898 for(auto y = 0; y < 16; ++y)
1899 {
1900 auto offs_x = (x+xoffs)%16, offs_y = (y+yoffs)%16;
1901 if(offs_x < 0) offs_x = (16 - abs(offs_x));
1902 if(offs_y < 0) offs_y = (16 - abs(offs_y));
1903 local_grid[offs_x][offs_y] = selection_grid[x+1][y+1]?1:0;
1904 }
1905 }
1906 for(auto x = 0; x < 16; ++x)
1907 {
1908 for(auto y = 0; y < 16; ++y)
1909 {
1910 selection_grid[x+1][y+1] = local_grid[x][y]?1:0;
1911 }
1912 }
1913 }
1914
1915 void show_edit_tile_help()
1916 {
1917 InfoDialog("Help: Tile Editor", "Hotkeys:"
1918 "\nF1: This Help Dialog"
1919 "\nEnter: Unfloat Sel / OK | Esc: Unfloat Sel / Cancel"
1920 "\nDelete: Clear Tile/Sel | Ctrl+Delete: Clear Tile"
1921 "\nA: Sel All | D: Unselect Sel | I: Invert Sel"
1922 "\nH/V: Flip | (Shift+)R: Rotate"
1923 "\n+/-: Change CSet | Ctrl +/-: Shift Colors"
1924 "\n(Ctrl+)S: Swap Colors | U/Ctrl+Z: Undo"
1925 "\nF12: Screenshot (whole screen)"
1926 "\nArrows: Shift Pixel | Ctrl+Arrows: Change Tile"
1927 "\nWhen not on Select tools, hold to swap:"
1928 "\nCtrl - Fill | Alt - Grab | Ctrl+Alt - Recolor").show();
1929 }
1930
1931 static int move_origin_x=-1, move_origin_y=-1;
1932 static int prev_x=-1, prev_y=-1;
1933 bool __pixel_draw(int x, int y, int tile, int flip)
1934 {
1935 bool ret = false;
1936 switch(tool)
1937 {
1938 case t_pen:
1939 if(flip&1) x=15-x;
1940
1941 if(flip&2) y=15-y;
1942
1943 if(is_in_selection(x,y))
1944 {
1945 if(floating_sel)
1946 {
1947 floatsel[(y<<4)+x]=(drawing==1)?c1:c2;
1948 }
1949 else
1950 {
1951 unpack_tile(newtilebuf, tile, 0, false);
1952 unpackbuf[((y<<4)+x)]=(drawing==1)?c1:c2;
1953 pack_tile(newtilebuf, unpackbuf,tile);
1954 }
1955 }
1956 break;
1957
1958 case t_fill:
1959 if(is_in_selection(x,y))
1960 {
1961 tile_floodfill(tile,x,y,(drawing==1)?c1:c2);
1962 ret = true;
1963 }
1964 break;
1965
1966 case t_recolor:
1967 if(is_in_selection(x,y))
1968 {
1969 if(floating_sel)
1970 {
1971 tf_u = floatsel[(y<<4)+x];
1972 for(int32_t i=0; i<256; i++)
1973 {
1974 if(is_in_selection(i&15,i>>4))
1975 {
1976 if(floatsel[i]==tf_u)
1977 {
1978 floatsel[i]=(drawing==1)?c1:c2;
1979 }
1980 }
1981 }
1982 }
1983 else
1984 {
1985 unpack_tile(newtilebuf, tile, 0, false);
1986 tf_u = unpackbuf[(y<<4)+x];
1987 if(tf_u != ((drawing==1)?c1:c2))
1988 {
1989 for(int32_t i=0; i<256; i++)
1990 {
1991 if(is_in_selection(i&15,i>>4))
1992 {
1993 if(unpackbuf[i]==tf_u)
1994 {
1995 unpackbuf[i]=(drawing==1)?c1:c2;
1996 }
1997 }
1998 }
1999
2000 pack_tile(newtilebuf, unpackbuf,tile);
2001 }
2002 }
2003 ret = true;
2004 }
2005 break;
2006
2007 case t_eyedropper:
2008 if(floating_sel)
2009 memcpy(unpackbuf, floatsel, 256);
2010 else unpack_tile(newtilebuf, tile, 0, false);
2011
2012 if(gui_mouse_b()&1)
2013 {
2014 c1=unpackbuf[((y<<4)+x)];
2015 }
2016
2017 if(gui_mouse_b()&2)
2018 {
2019 c2=unpackbuf[((y<<4)+x)];
2020 }
2021 break;
2022
2023 case t_move:
2024 if((prev_x!=x)||(prev_y!=y))
2025 {
2026 if(has_selection())
2027 {
2028 float_selection(tile,key[KEY_LSHIFT]||key[KEY_RSHIFT]);
2029 wrap_sel_tile(y-prev_y, x-prev_x);
2030 shift_selection_grid(x-prev_x, y-prev_y);
2031 }
2032 else wrap_tile(tile, y-move_origin_y, x-move_origin_x, drawing==2);
2033 prev_x=x;
2034 prev_y=y;
2035 }
2036 break;
2037
2038 case t_select:
2039 unfloat_selection();
2040 if(flip&1) x=15-x;
2041
2042 if(flip&2) y=15-y;
2043
2044 if(selecting_x1==-1||selecting_y1==-1)
2045 {
2046 selecting_x1=x;
2047 selecting_y1=y;
2048 }
2049 else
2050 {
2051 selecting_x2=x;
2052 selecting_y2=y;
2053 }
2054 break;
2055
2056 case t_wand:
2057 unfloat_selection();
2058 if(flip&1) x=15-x;
2059
2060 if(flip&2) y=15-y;
2061
2062 switch(select_mode)
2063 {
2064 case 0:
2065 clear_selection_grid();
2066 add_color_to_selection(unpackbuf[((y<<4)+x)]);
2067 break;
2068
2069 case 1:
2070 add_color_to_selection(unpackbuf[((y<<4)+x)]);
2071 break;
2072
2073 case 2:
2074 remove_color_from_selection(unpackbuf[((y<<4)+x)]);
2075 break;
2076
2077 case 3:
2078 intersect_color_with_selection(unpackbuf[((y<<4)+x)]);
2079 break;
2080 }
2081
2082 ret = true;
2083 break;
2084 }
2085 return ret;
2086 }
2087 void edit_tile(int32_t tile,int32_t flip,int32_t &cs)
2088 {
2089 popup_zqdialog_start();
2090 FONT* oldfont = font;
2091 font = get_custom_font(CFONT_DLG);
2092 edit_button.h = ok_button.h = cancel_button.h = 12+text_height(font);
2093 status_info.yscale = text_height(font);
2094 status_info.y = 308-(status_info.h*status_info.yscale);
2095 hover_info.yscale = status_info.yscale;
2096 hover_info.y = 338-(hover_info.h*hover_info.yscale);
2097 undocount = tilesize(newtilebuf[tile].format);
2098 clear_selection_grid();
2099 selecting_x1=selecting_x2=selecting_y1=selecting_y2=-1;
2100
2101 tthighlight = zc_get_config("ZQ_GUI","tile_edit_fancyhighlight",1);
2102 showcolortip = zc_get_config("ZQ_GUI","tile_edit_colornames",1);
2103
2104 PALETTE tpal;
2105 byte oldtile[256];
2106
2107 memset(&tpal, 0, sizeof(PALETTE));
2108 memset(oldtile, 0, 256);
2109
2110 for(int32_t i=0; i<undocount; i++)
2111 {
2112 oldtile[i]=undotile[i]=newtilebuf[tile].data[i];
2113 }
2114 byte undoselgrid[16][16];
2115 for(auto x = 0; x < 16; ++x)
2116 for(auto y = 0; y < 16; ++y)
2117 undoselgrid[x][y] = selection_grid[x+1][y+1];
2118 for(auto q = 0; q < 256; ++q)
2119 {
2120 floatsel[q] = 0;
2121 undofloatsel[q] = 0;
2122 floating_sel = false;
2123 undo_is_floatsel = false;
2124 }
2125
2126 int32_t tile_x=-1, tile_y=-1;
2127 int32_t temp_x=-1, temp_y=-1;
2128 bool bdown=false;
2129 int32_t done=0;
2130 drawing=0;
2131 tool_cur = -1;
2132
2133 get_palette(tpal);
2134
2135 if(newtilebuf[tile].format==tf4Bit)
2136 {
2137 invcol=makecol8(255 - tpal[CSET(cs)].r, 255 - tpal[CSET(cs)].g, 255 - tpal[CSET(cs)].b);
2138 }
2139 else
2140 {
2141 invcol=makecol8(255 - tpal[0].r, 255 - tpal[0].g, 255 - tpal[0].b);
2142 }
2143
2144 zc_set_palette(tpal);
2145 draw_edit_scr(tile,flip,cs,oldtile, true);
2146 anim_hw_screen();
2147 while(gui_mouse_b()) ; // wait
2148
2149 move_origin_x=-1;
2150 move_origin_y=-1;
2151 prev_x=-1;
2152 prev_y=-1;
2153
2154
2155
2156 byte selection_pattern_source[8][8]=
2157 {
2158 {1, 1, 1, 1, 0, 0, 0, 0},
2159 {1, 1, 1, 0, 0, 0, 0, 1},
2160 {1, 1, 0, 0, 0, 0, 1, 1},
2161 {1, 0, 0, 0, 0, 1, 1, 1},
2162 {0, 0, 0, 0, 1, 1, 1, 1},
2163 {0, 0, 0, 1, 1, 1, 1, 0},
2164 {0, 0, 1, 1, 1, 1, 0, 0},
2165 {0, 1, 1, 1, 1, 0, 0, 0},
2166 };
2167
2168 byte selecting_pattern_source[8][8]=
2169 {
2170 {1, 1, 0, 0, 0, 0, 1, 1},
2171 {1, 0, 0, 0, 0, 1, 1, 1},
2172 {0, 0, 0, 0, 1, 1, 1, 1},
2173 {0, 0, 0, 1, 1, 1, 1, 0},
2174 {0, 0, 1, 1, 1, 1, 0, 0},
2175 {0, 1, 1, 1, 1, 0, 0, 0},
2176 {1, 1, 1, 1, 0, 0, 0, 0},
2177 {1, 1, 1, 0, 0, 0, 0, 1},
2178 };
2179
2180 byte intersection_pattern_source[8][8]=
2181 {
2182 {0, 0, 1, 1, 0, 0, 1, 1},
2183 {0, 1, 1, 0, 0, 1, 1, 0},
2184 {1, 1, 0, 0, 1, 1, 0, 0},
2185 {1, 0, 0, 1, 1, 0, 0, 1},
2186 {0, 0, 1, 1, 0, 0, 1, 1},
2187 {0, 1, 1, 0, 0, 1, 1, 0},
2188 {1, 1, 0, 0, 1, 1, 0, 0},
2189 {1, 0, 0, 1, 1, 0, 0, 1},
2190 };
2191
2192 selection_pattern=create_bitmap_ex(8, 8, 8);
2193
2194 for(int32_t x=0; x<8; ++x)
2195 {
2196 for(int32_t y=0; y<8; ++y)
2197 {
2198 selection_pattern->line[y][x]=selection_pattern_source[x][y]?vc(0):vc(15);
2199 }
2200 }
2201
2202 selecting_pattern=create_bitmap_ex(8, 8, 8);
2203
2204 for(int32_t x=0; x<8; ++x)
2205 {
2206 for(int32_t y=0; y<8; ++y)
2207 {
2208 selecting_pattern->line[y][x]=selecting_pattern_source[x][y]?vc(0):vc(15);
2209 }
2210 }
2211
2212 intersection_pattern=create_bitmap_ex(8, 8, 8);
2213
2214 for(int32_t x=0; x<8; ++x)
2215 {
2216 for(int32_t y=0; y<8; ++y)
2217 {
2218 intersection_pattern->line[y][x]=intersection_pattern_source[x][y]?vc(0):vc(15);
2219 }
2220 }
2221
2222 do
2223 {
2224 HANDLE_CLOSE_ZQDLG();
2225 if(exiting_program) break;
2226 int32_t temp_mouse_x=gui_mouse_x();
2227 int32_t temp_mouse_y=gui_mouse_y();
2228 //rest(4);
2229 bool redraw=false;
2230 bool did_wand_select=false;
2231
2232 if(keypressed())
2233 {
2234 bool ctrl = CHECK_CTRL_CMD;
2235 int k = readkey()>>8;
2236 switch(k)
2237 {
2238 case KEY_F1:
2239 show_edit_tile_help();
2240 break;
2241 case KEY_ENTER_PAD:
2242 case KEY_ENTER:
2243 if(floating_sel)
2244 unfloat_selection();
2245 else done=2;
2246 break;
2247
2248 case KEY_ESC:
2249 if(floating_sel)
2250 unfloat_selection();
2251 else if(has_selection())
2252 clear_selection_grid();
2253 else done=1;
2254 break;
2255
2256 case KEY_DEL:
2257 {
2258 unpack_tile(newtilebuf, tile, 0, false);
2259 bool all = CHECK_CTRL_CMD || !has_selection();
2260 bool canDel = false;
2261 if(all)
2262 {
2263 //Check all
2264 for(auto q = 0; q < 256; ++q)
2265 if(unpackbuf[q])
2266 {
2267 canDel = true;
2268 break;
2269 }
2270 }
2271 else
2272 {
2273 //Check selection
2274 for(auto x = 0; x < 16; ++x)
2275 for(auto y = 0; y < 16; ++y)
2276 if(is_in_selection(x,y))
2277 if(unpackbuf[(y<<4)+x])
2278 {
2279 canDel = true;
2280 break;
2281 }
2282 }
2283 if(!canDel) break; //don't delete (and thus reset undo) if nothing would change!
2284
2285 for(int32_t i=0; i<undocount; i++)
2286 {
2287 undotile[i]=newtilebuf[tile].data[i];
2288 }
2289 for(auto x = 0; x < 16; ++x)
2290 for(auto y = 0; y < 16; ++y)
2291 undoselgrid[x][y] = selection_grid[x+1][y+1];
2292 for(auto q = 0; q < 256; ++q)
2293 undofloatsel[q] = floatsel[q];
2294 undo_is_floatsel = floating_sel;
2295
2296 if(CHECK_CTRL_CMD || !has_selection())
2297 {
2298 //Delete all
2299 for(auto q = 0; q < 256; ++q)
2300 {
2301 unpackbuf[q] = 0;
2302 floatsel[q] = 0;
2303 }
2304 }
2305 else
2306 {
2307 //Delete selection
2308 for(auto x = 0; x < 16; ++x)
2309 for(auto y = 0; y < 16; ++y)
2310 {
2311 if(floating_sel)
2312 {
2313 floatsel[x+(y<<4)] = 0;
2314 }
2315 else if(is_in_selection(x,y))
2316 {
2317 unpackbuf[(y<<4)+x] = 0;
2318 }
2319 }
2320 }
2321 pack_tile(newtilebuf, unpackbuf, tile);
2322 redraw=true;
2323 }
2324 break;
2325
2326 case KEY_A:
2327 clear_selection_grid();
2328 invert_selection_grid();
2329 redraw=true;
2330 break;
2331
2332 case KEY_D:
2333 clear_selection_grid();
2334 redraw=true;
2335 break;
2336
2337 case KEY_I:
2338 invert_selection_grid();
2339 redraw=true;
2340 break;
2341
2342 case KEY_H:
2343 flip^=1;
2344 normalize(tile,tile,0,flip);
2345 flip=0;
2346 redraw=true;
2347 break;
2348
2349 case KEY_V:
2350 flip^=2;
2351 normalize(tile,tile,0,flip);
2352 flip=0;
2353 redraw=true;
2354 break;
2355
2356 case KEY_F12:
2357 onSnapshot();
2358 break;
2359
2360 case KEY_R:
2361 {
2362 //if(CHECK_CTRL_CMD))
2363 // {
2364 //do_recolor(tile); redraw=true; mark_save_dirty();
2365 // }
2366 //else
2367 // {
2368 go_tiles();
2369 rotate_tile(tile,(key[KEY_LSHIFT] || key[KEY_RSHIFT]));
2370 redraw=true;
2371 mark_save_dirty();
2372 break;
2373 }
2374
2375 case KEY_EQUALS:
2376 case KEY_PLUS_PAD:
2377 {
2378 if(CHECK_CTRL_CMD ||
2379 key[KEY_ALT] || key[KEY_ALTGR])
2380 {
2381 for(int32_t i=0; i<undocount; i++)
2382 undotile[i]=newtilebuf[tile].data[i];
2383 for(auto x = 0; x < 16; ++x)
2384 for(auto y = 0; y < 16; ++y)
2385 undoselgrid[x][y] = selection_grid[x+1][y+1];
2386 for(auto q = 0; q < 256; ++q)
2387 undofloatsel[q] = floatsel[q];
2388 undo_is_floatsel = floating_sel;
2389
2390 if(key[KEY_ALT] || key[KEY_ALTGR])
2391 shift_tile_colors(tile, 16, false);
2392 else
2393 shift_tile_colors(tile, 1, key[KEY_LSHIFT] || key[KEY_RSHIFT]);
2394 }
2395 else
2396 cs = (cs<13) ? cs+1:0;
2397
2398 redraw=true;
2399 break;
2400 }
2401
2402 case KEY_MINUS:
2403 case KEY_MINUS_PAD:
2404 {
2405 if(CHECK_CTRL_CMD ||
2406 key[KEY_ALT] || key[KEY_ALTGR])
2407 {
2408 for(int32_t i=0; i<undocount; i++)
2409 undotile[i]=newtilebuf[tile].data[i];
2410 for(auto x = 0; x < 16; ++x)
2411 for(auto y = 0; y < 16; ++y)
2412 undoselgrid[x][y] = selection_grid[x+1][y+1];
2413 for(auto q = 0; q < 256; ++q)
2414 undofloatsel[q] = floatsel[q];
2415 undo_is_floatsel = floating_sel;
2416
2417 if(key[KEY_ALT] || key[KEY_ALTGR])
2418 shift_tile_colors(tile, -16, false);
2419 else
2420 shift_tile_colors(tile, -1, key[KEY_LSHIFT] || key[KEY_RSHIFT]);
2421 }
2422 else
2423 cs = (cs>0) ? cs-1:13;
2424
2425 redraw=true;
2426 break;
2427 }
2428
2429 case KEY_SPACE:
2430 gridmode=(gridmode+1)%gm_max;
2431 redraw=true;
2432 break;
2433
2434 case KEY_Z:
2435 if(!ctrl)
2436 break;
2437 //Ctrl+Z == undo
2438 [[fallthrough]];
2439 case KEY_U:
2440 for(int32_t i=0; i<undocount; i++)
2441 zc_swap(undotile[i],newtilebuf[tile].data[i]);
2442
2443 for(auto x = 0; x < 16; ++x)
2444 for(auto y = 0; y < 16; ++y)
2445 zc_swap(selection_grid[x+1][y+1], undoselgrid[x][y]);
2446
2447 for(auto q = 0; q < 256; ++q)
2448 zc_swap(undofloatsel[q], floatsel[q]);
2449 zc_swap(undo_is_floatsel, floating_sel);
2450
2451 redraw=true;
2452 break;
2453
2454 case KEY_S:
2455 if(CHECK_CTRL_CMD)
2456 {
2457 for(int32_t i=0; i<undocount; i++)
2458 {
2459 undotile[i]=newtilebuf[tile].data[i];
2460 }
2461 for(auto x = 0; x < 16; ++x)
2462 for(auto y = 0; y < 16; ++y)
2463 undoselgrid[x][y] = selection_grid[x+1][y+1];
2464 for(auto q = 0; q < 256; ++q)
2465 undofloatsel[q] = floatsel[q];
2466 undo_is_floatsel = floating_sel;
2467
2468 unpack_tile(newtilebuf, tile, 0, false);
2469
2470 if(has_selection())
2471 {
2472 for(int32_t i=0; i<256; i++)
2473 {
2474 if(!is_in_selection(i%16,i/16))
2475 continue;
2476 if(unpackbuf[i]==c1)
2477 {
2478 unpackbuf[i]=c2;
2479 }
2480 else if(unpackbuf[i]==c2)
2481 {
2482 unpackbuf[i]=c1;
2483 }
2484 if(floating_sel)
2485 {
2486 if(floatsel[i]==c1)
2487 {
2488 floatsel[i]=c2;
2489 }
2490 else if(floatsel[i]==c2)
2491 {
2492 floatsel[i]=c1;
2493 }
2494 }
2495 }
2496 }
2497 else
2498 {
2499 for(int32_t i=0; i<256; i++)
2500 {
2501 if(unpackbuf[i]==c1)
2502 {
2503 unpackbuf[i]=c2;
2504 }
2505 else if(unpackbuf[i]==c2)
2506 {
2507 unpackbuf[i]=c1;
2508 }
2509 }
2510 }
2511
2512 pack_tile(newtilebuf, unpackbuf,tile);
2513 }
2514
2515 zc_swap(c1,c2);
2516 redraw=true;
2517 break;
2518
2519 case KEY_UP:
2520 if(CHECK_CTRL_CMD)
2521 {
2522 unfloat_selection();
2523 tile=zc_max(0,tile-TILES_PER_ROW);
2524 undocount = tilesize(newtilebuf[tile].format);
2525
2526 for(int32_t i=0; i<undocount; i++)
2527 {
2528 undotile[i]=newtilebuf[tile].data[i];
2529 oldtile[i]=undotile[i];
2530 }
2531
2532 redraw=true;
2533 }
2534 else
2535 {
2536 for(int32_t i=0; i<undocount; i++)
2537 {
2538 undotile[i]=newtilebuf[tile].data[i];
2539 }
2540 for(auto x = 0; x < 16; ++x)
2541 for(auto y = 0; y < 16; ++y)
2542 undoselgrid[x][y] = selection_grid[x+1][y+1];
2543 for(auto q = 0; q < 256; ++q)
2544 undofloatsel[q] = floatsel[q];
2545 undo_is_floatsel = floating_sel;
2546 if(has_selection())
2547 {
2548 float_selection(tile,key[KEY_LSHIFT]||key[KEY_RSHIFT]);
2549 wrap_sel_tile(-1, 0);
2550 shift_selection_grid(0, -1);
2551 }
2552 else wrap_tile(tile, -1, 0, false);
2553 redraw=true;
2554 }
2555 break;
2556
2557 case KEY_DOWN:
2558 if(CHECK_CTRL_CMD)
2559 {
2560 unfloat_selection();
2561 tile=zc_min(tile+TILES_PER_ROW,NEWMAXTILES-1);
2562 undocount = tilesize(newtilebuf[tile].format);
2563
2564 for(int32_t i=0; i<undocount; i++)
2565 {
2566 undotile[i]=newtilebuf[tile].data[i];
2567 oldtile[i]=undotile[i];
2568 }
2569
2570 redraw=true;
2571 }
2572 else
2573 {
2574 for(int32_t i=0; i<undocount; i++)
2575 {
2576 undotile[i]=newtilebuf[tile].data[i];
2577 }
2578 for(auto x = 0; x < 16; ++x)
2579 for(auto y = 0; y < 16; ++y)
2580 undoselgrid[x][y] = selection_grid[x+1][y+1];
2581 for(auto q = 0; q < 256; ++q)
2582 undofloatsel[q] = floatsel[q];
2583 undo_is_floatsel = floating_sel;
2584 if(has_selection())
2585 {
2586 float_selection(tile,key[KEY_LSHIFT]||key[KEY_RSHIFT]);
2587 wrap_sel_tile(1, 0);
2588 shift_selection_grid(0, 1);
2589 }
2590 else wrap_tile(tile, 1, 0, false);
2591 redraw=true;
2592 }
2593 break;
2594
2595 case KEY_LEFT:
2596 if(CHECK_CTRL_CMD)
2597 {
2598 unfloat_selection();
2599 tile=zc_max(0,tile-1);
2600 undocount = tilesize(newtilebuf[tile].format);
2601
2602 for(int32_t i=0; i<undocount; i++)
2603 {
2604 undotile[i]=newtilebuf[tile].data[i];
2605 oldtile[i]=undotile[i];
2606 }
2607
2608 redraw=true;
2609 }
2610 else
2611 {
2612 for(int32_t i=0; i<undocount; i++)
2613 {
2614 undotile[i]=newtilebuf[tile].data[i];
2615 }
2616 for(auto x = 0; x < 16; ++x)
2617 for(auto y = 0; y < 16; ++y)
2618 undoselgrid[x][y] = selection_grid[x+1][y+1];
2619 for(auto q = 0; q < 256; ++q)
2620 undofloatsel[q] = floatsel[q];
2621 undo_is_floatsel = floating_sel;
2622 if(has_selection())
2623 {
2624 float_selection(tile,key[KEY_LSHIFT]||key[KEY_RSHIFT]);
2625 wrap_sel_tile(0, -1);
2626 shift_selection_grid(-1, 0);
2627 }
2628 else wrap_tile(tile, 0, -1, false);
2629 redraw=true;
2630 }
2631 break;
2632
2633 case KEY_RIGHT:
2634 if(CHECK_CTRL_CMD)
2635 {
2636 unfloat_selection();
2637 tile=zc_min(tile+1, NEWMAXTILES-1);
2638 undocount = tilesize(newtilebuf[tile].format);
2639
2640 for(int32_t i=0; i<undocount; i++)
2641 {
2642 undotile[i]=newtilebuf[tile].data[i];
2643 oldtile[i]=undotile[i];
2644 }
2645
2646 redraw=true;
2647 }
2648 else
2649 {
2650 for(int32_t i=0; i<undocount; i++)
2651 {
2652 undotile[i]=newtilebuf[tile].data[i];
2653 }
2654 for(auto x = 0; x < 16; ++x)
2655 for(auto y = 0; y < 16; ++y)
2656 undoselgrid[x][y] = selection_grid[x+1][y+1];
2657 for(auto q = 0; q < 256; ++q)
2658 undofloatsel[q] = floatsel[q];
2659 undo_is_floatsel = floating_sel;
2660 if(has_selection())
2661 {
2662 float_selection(tile,key[KEY_LSHIFT]||key[KEY_RSHIFT]);
2663 wrap_sel_tile(0, 1);
2664 shift_selection_grid(1, 0);
2665 }
2666 else wrap_tile(tile, 0, 1, false);
2667 redraw=true;
2668 }
2669 break;
2670 case KEY_0: case KEY_1: case KEY_2: case KEY_3:
2671 case KEY_4: case KEY_5: case KEY_6: case KEY_7:
2672 case KEY_8: case KEY_9:
2673 case KEY_0_PAD: case KEY_1_PAD: case KEY_2_PAD: case KEY_3_PAD:
2674 case KEY_4_PAD: case KEY_5_PAD: case KEY_6_PAD: case KEY_7_PAD:
2675 case KEY_8_PAD: case KEY_9_PAD:
2676 {
2677 int t = k - ((k>KEY_9) ? KEY_1_PAD : KEY_1);
2678 if(unsigned(t) < t_max)
2679 {
2680 if(old_tool != -1)
2681 old_tool = t;
2682 else tool = t;
2683 }
2684 break;
2685 }
2686 case KEY_TAB:
2687 {
2688 if(key_shifts & KB_CTRL_CMD_FLAG)
2689 {
2690 xmode = (xmode+1)%XMODE_MAX;
2691 if(!xmode)
2692 bgmode = (bgmode+1)%BGMODE_MAX;
2693 }
2694 else if(key_shifts & KB_SHIFT_FLAG)
2695 hide_grid = !hide_grid;
2696 else show_quartgrid = !show_quartgrid;
2697 redraw = true;
2698 break;
2699 }
2700 }
2701 clear_keybuf();
2702 }
2703
2704 if(!gui_mouse_b())
2705 {
2706 if(is_selecting())
2707 {
2708 unfloat_selection();
2709 int32_t x1=zc_min(selecting_x1,selecting_x2);
2710 int32_t x2=zc_max(selecting_x1,selecting_x2);
2711 int32_t y1=zc_min(selecting_y1,selecting_y2);
2712 int32_t y2=zc_max(selecting_y1,selecting_y2);
2713
2714 if(select_mode==0)
2715 {
2716 clear_selection_grid();
2717 }
2718
2719 for(int32_t x=x1; x<=x2; ++x)
2720 {
2721 for(int32_t y=y1; y<=y2; ++y)
2722 {
2723 selection_grid[x+1][y+1]=((select_mode<2)?(1):(((select_mode==2)?(0):(selection_grid[x+1][y+1]))));
2724 }
2725 }
2726
2727 if(select_mode==3)
2728 {
2729 for(int32_t y=0; y<16; ++y)
2730 {
2731 for(int32_t x=0; x<x1; ++x)
2732 {
2733 selection_grid[x+1][y+1]=0;
2734 }
2735
2736 for(int32_t x=x2+1; x<16; ++x)
2737 {
2738 selection_grid[x+1][y+1]=0;
2739 }
2740 }
2741
2742 for(int32_t x=x1; x<=x2; ++x)
2743 {
2744 for(int32_t y=0; y<y1; ++y)
2745 {
2746 selection_grid[x+1][y+1]=0;
2747 }
2748
2749 for(int32_t y=y2+1; y<16; ++y)
2750 {
2751 selection_grid[x+1][y+1]=0;
2752 }
2753 }
2754 }
2755 }
2756
2757 selecting_x1=selecting_x2=selecting_y1=selecting_y2=-1;
2758 did_wand_select=false;
2759 }
2760
2761 bool alt=(key[KEY_ALT]||key[KEY_ALTGR]);
2762 bool shift=(key[KEY_LSHIFT] || key[KEY_RSHIFT]);
2763 bool ctrl=CHECK_CTRL_CMD;
2764 static int32_t last_tool_val = 0;
2765
2766 if(tool==t_select||tool==t_wand)
2767 {
2768 if(!drawing)
2769 {
2770 int32_t type=0;
2771
2772 if(has_selection())
2773 {
2774 if(shift)
2775 {
2776 type+=1;
2777 }
2778
2779 if(alt)
2780 {
2781 type+=2;
2782 }
2783 }
2784
2785 if(type!=select_mode)
2786 {
2787 select_mode=type;
2788
2789 if(isinRect(temp_mouse_x,temp_mouse_y-(tool==t_fill ? (14) : 0),zoomtile.x,zoomtile.y,zoomtile.x+(zoomtile.w*zoomtile.xscale)-2,zoomtile.y+(zoomtile.h*zoomtile.yscale)-2-(tool==t_fill ? (14) : 0))) //inside the zoomed tile window
2790 set_tool_sprite(tool,type);
2791 }
2792 }
2793 }
2794 else if(alt||ctrl)
2795 {
2796 if(old_tool==-1)
2797 {
2798 old_tool = tool;
2799 tool_cur = -1;
2800 }
2801 if(alt&&ctrl)
2802 tool = t_recolor;
2803 else if(alt)
2804 tool = t_eyedropper;
2805 else tool = t_fill;
2806 }
2807 else if(old_tool!=-1)
2808 {
2809 tool = old_tool;
2810 old_tool = -1;
2811 tool_cur = -1;
2812 redraw = true;
2813 }
2814 if(last_tool_val != tool)
2815 {
2816 redraw = true;
2817 tool_cur = -1;
2818 update_tool_cursor();
2819 last_tool_val = tool;
2820 }
2821
2822 if(!bdown)
2823 {
2824 move_origin_x=prev_x=(temp_mouse_x-zoomtile.x)/zoomtile.xscale;
2825 move_origin_y=prev_y=(temp_mouse_y-zoomtile.y)/zoomtile.yscale;
2826 }
2827
2828 if(gui_mouse_b()==1 && !bdown) //pressed the left mouse button
2829 {
2830 if(isinRect(temp_mouse_x,temp_mouse_y,zoomtile.x,zoomtile.y-(tool==t_fill ? (14) : 0),zoomtile.x+(zoomtile.w*zoomtile.xscale)-2,zoomtile.y+(zoomtile.h*zoomtile.yscale)-2-(tool==t_fill ? (14) : 0))) //inside the zoomed tile window
2831 {
2832 if(tool==t_move || tool==t_fill)
2833 {
2834 set_tool_sprite(tool,1);
2835
2836 move_origin_x=prev_x=(temp_mouse_x-zoomtile.x)/zoomtile.xscale;
2837 move_origin_y=prev_y=(temp_mouse_y-zoomtile.y)/zoomtile.yscale;
2838 }
2839
2840 for(int32_t i=0; i<undocount; i++)
2841 {
2842 undotile[i]=newtilebuf[tile].data[i];
2843 }
2844 for(auto x = 0; x < 16; ++x)
2845 for(auto y = 0; y < 16; ++y)
2846 undoselgrid[x][y] = selection_grid[x+1][y+1];
2847 for(auto q = 0; q < 256; ++q)
2848 undofloatsel[q] = floatsel[q];
2849 undo_is_floatsel = floating_sel;
2850
2851 drawing=1;
2852 }
2853
2854 if(ok_button.rect(temp_mouse_x,temp_mouse_y))
2855 {
2856 if(do_text_button(ok_button.x,ok_button.y,ok_button.w,ok_button.h,"OK"))
2857 {
2858 done=2;
2859 }
2860 }
2861
2862 if(cancel_button.rect(temp_mouse_x,temp_mouse_y))
2863 {
2864 if(do_text_button(cancel_button.x,cancel_button.y,cancel_button.w,cancel_button.h,"Cancel"))
2865 {
2866 done=1;
2867 }
2868 }
2869
2870 if(edit_button.rect(temp_mouse_x,temp_mouse_y))
2871 {
2872 if(do_text_button(edit_button.x,edit_button.y,edit_button.w,edit_button.h,"Edit Pal"))
2873 {
2874 colors_menu.pop(edit_button.x+2,edit_button.y-40);
2875 get_palette(tpal);
2876
2877 if(newtilebuf[tile].format==tf4Bit)
2878 {
2879 invcol=makecol8(255 - tpal[CSET(cs)].r, 255 - tpal[CSET(cs)].g, 255 - tpal[CSET(cs)].b);
2880 }
2881 else
2882 {
2883 invcol=makecol8(255 - tpal[0].r, 255 - tpal[0].g, 255 - tpal[0].b);
2884 }
2885
2886 redraw=true;
2887 }
2888 }
2889
2890 int sqr_clicked;
2891 if(show_quartgrid && qgrid_tool(tool))
2892 {
2893 sqr_clicked = reflbtn_grid.rectind(temp_mouse_x,temp_mouse_y);
2894 if(sqr_clicked > -1)
2895 {
2896 auto& sqr = reflbtn_grid.subsquare(sqr_clicked);
2897 if(do_text_button(sqr.x,sqr.y,sqr.w,sqr.h,reflbtn_names[sqr_clicked]))
2898 refl_flags ^= (1<<sqr_clicked);
2899 }
2900 }
2901 sqr_clicked = xmodebtn_grid.rectind(temp_mouse_x,temp_mouse_y);
2902 if(sqr_clicked > -1)
2903 {
2904 auto& sqr = xmodebtn_grid.subsquare(sqr_clicked);
2905 if(do_text_button(sqr.x,sqr.y,sqr.w,sqr.h,xmodebtn_names[sqr_clicked]))
2906 xmode = sqr_clicked;
2907 }
2908 sqr_clicked = bgmodebtn_grid.rectind(temp_mouse_x,temp_mouse_y);
2909 if(sqr_clicked > -1)
2910 {
2911 auto& sqr = bgmodebtn_grid.subsquare(sqr_clicked);
2912 if(do_text_button(sqr.x,sqr.y,sqr.w,sqr.h,bgmodebtn_names[sqr_clicked]))
2913 bgmode = sqr_clicked;
2914 }
2915
2916 if(showcolortip)
2917 {
2918 auto oy = color_info.y;
2919 if(reftile <= 0)
2920 color_info.y -= ref_til.h + 8;
2921 if(color_info.rect(temp_mouse_x,temp_mouse_y))
2922 {
2923 showcolortip = 0;
2924 zc_set_config("ZQ_GUI","tile_edit_colornames",0);
2925 }
2926 color_info.y = oy;
2927 }
2928 else
2929 {
2930 auto oy = color_info_btn.y;
2931 if(reftile <= 0)
2932 color_info_btn.y -= ref_til.h + 8;
2933 if(color_info_btn.rect(temp_mouse_x,temp_mouse_y))
2934 {
2935 if(do_text_button(color_info_btn.x,color_info_btn.y,color_info_btn.w,color_info_btn.h,"Show Colors"))
2936 {
2937 showcolortip = 1;
2938 zc_set_config("ZQ_GUI","tile_edit_colornames",1);
2939 redraw=true;
2940 }
2941 }
2942 color_info_btn.y = oy;
2943 }
2944
2945 if(hlcbox.rect(temp_mouse_x,temp_mouse_y))
2946 {
2947 if(do_checkbox(screen2,hlcbox.x,hlcbox.y,hlcbox.w,hlcbox.h,tthighlight))
2948 {
2949 zc_set_config("ZQ_GUI","tile_edit_fancyhighlight",tthighlight);
2950 redraw=true;
2951 }
2952 }
2953 if(quartgrid_cbox.rect(temp_mouse_x,temp_mouse_y))
2954 {
2955 if(do_checkbox(screen2,quartgrid_cbox.x,quartgrid_cbox.y,quartgrid_cbox.w,quartgrid_cbox.h,show_quartgrid))
2956 redraw=true;
2957 }
2958 if(hidegrid_cbox.rect(temp_mouse_x,temp_mouse_y))
2959 {
2960 if(do_checkbox(screen2,hidegrid_cbox.x,hidegrid_cbox.y,hidegrid_cbox.w,hidegrid_cbox.h,hide_grid))
2961 redraw=true;
2962 }
2963
2964 switch(newtilebuf[tile].format)
2965 {
2966 case tf4Bit:
2967 {
2968 auto ind = cpalette_4.rectind(temp_mouse_x,temp_mouse_y);
2969 if(ind > -1)
2970 {
2971 c1 = ind;
2972 redraw=true;
2973 }
2974 break;
2975 }
2976 case tf8Bit:
2977 {
2978 auto ind = cpalette_8.rectind(temp_mouse_x,temp_mouse_y);
2979 if(ind > -1)
2980 {
2981 c1 = ind;
2982 redraw=true;
2983 }
2984 break;
2985 }
2986 }
2987
2988
2989 int32_t newtool = tool_btns.rectind(temp_mouse_x,temp_mouse_y);
2990 if(newtool > -1 && newtool < t_max)
2991 {
2992 tool=newtool;
2993 redraw=true;
2994 }
2995
2996 if(x_btn.rect(temp_mouse_x,temp_mouse_y))
2997 {
2998 if(do_x_button(screen, x_btn.x, x_btn.y))
2999 {
3000 done=1;
3001 }
3002 }
3003 if(info_btn.rect(temp_mouse_x,temp_mouse_y))
3004 {
3005 if(do_question_button(screen, info_btn.x, info_btn.y))
3006 {
3007 show_edit_tile_help();
3008 }
3009 }
3010
3011 bdown=true;
3012 }
3013
3014 if(gui_mouse_b()&2 && !bdown) //pressed the right mouse button
3015 {
3016 if(isinRect(temp_mouse_x,temp_mouse_y,zoomtile.x,zoomtile.y-(tool==t_fill ? (14) : 0),zoomtile.x+(zoomtile.w*zoomtile.xscale)-2,zoomtile.y+(zoomtile.h*zoomtile.yscale)-2-(tool==t_fill ? (14) : 0))) //inside the zoomed tile window
3017 {
3018 if(tool==t_move || tool==t_fill)
3019 {
3020 set_tool_sprite(tool,1);
3021
3022 move_origin_x=prev_x=(temp_mouse_x-zoomtile.x)/zoomtile.xscale;
3023 move_origin_y=prev_y=(temp_mouse_y-zoomtile.y)/zoomtile.yscale;
3024 }
3025
3026 for(int32_t i=0; i<undocount; i++)
3027 {
3028 undotile[i]=newtilebuf[tile].data[i];
3029 }
3030 for(auto x = 0; x < 16; ++x)
3031 for(auto y = 0; y < 16; ++y)
3032 undoselgrid[x][y] = selection_grid[x+1][y+1];
3033 for(auto q = 0; q < 256; ++q)
3034 undofloatsel[q] = floatsel[q];
3035 undo_is_floatsel = floating_sel;
3036
3037 drawing=2;
3038 }
3039
3040 switch(newtilebuf[tile].format)
3041 {
3042 case tf4Bit:
3043 {
3044 auto ind = cpalette_4.rectind(temp_mouse_x,temp_mouse_y);
3045 if(ind > -1)
3046 {
3047 c2 = ind;
3048 redraw=true;
3049 }
3050 break;
3051 }
3052 case tf8Bit:
3053 {
3054 auto ind = cpalette_8.rectind(temp_mouse_x,temp_mouse_y);
3055 if(ind > -1)
3056 {
3057 c2 = ind;
3058 redraw=true;
3059 }
3060 break;
3061 }
3062 }
3063
3064 bdown=true;
3065 }
3066
3067 if(bdown&&!gui_mouse_b()) //released the buttons
3068 {
3069 if(isinRect(temp_mouse_x,temp_mouse_y,zoomtile.x,zoomtile.y-(tool==t_fill ? (14) : 0),zoomtile.x+(zoomtile.w*zoomtile.xscale)-2,zoomtile.y+(zoomtile.h*zoomtile.yscale)-2-(tool==t_fill ? (14) : 0))) //inside the zoomed tile window
3070 {
3071 if(tool==t_move || tool==t_fill)
3072 {
3073 set_tool_sprite(tool,0);
3074 }
3075 }
3076 }
3077
3078 if(drawing && zoomtile.rect(temp_mouse_x,temp_mouse_y)) //inside the zoomed tile window
3079 {
3080 int32_t ind = zoomtile.rectind(temp_mouse_x,temp_mouse_y);
3081 int32_t x=ind%zoomtile.w;
3082 int32_t y=ind/zoomtile.w;
3083
3084 bool reset_draw = false;
3085
3086 if(__pixel_draw(x,y,tile,flip))
3087 reset_draw = true;
3088 if(show_quartgrid)
3089 {
3090 auto tmp_sel_mode = select_mode;
3091 if(tool == t_wand && select_mode == 0)
3092 select_mode = 1;
3093 if(qgrid_tool(tool))
3094 {
3095 if(refl_flags & (1<<REFL_HFLIP))
3096 if(__pixel_draw(15-x,y,tile,flip))
3097 reset_draw = true;
3098 if(refl_flags & (1<<REFL_VFLIP))
3099 if(__pixel_draw(x,15-y,tile,flip))
3100 reset_draw = true;
3101 //Diagonal flip and 180° rotation are the same!
3102 if(refl_flags & ((1<<REFL_DBLFLIP)|(1<<REFL_180)))
3103 if(__pixel_draw(15-x,15-y,tile,flip))
3104 reset_draw = true;
3105 if(refl_flags & (1<<REFL_90CW))
3106 if(__pixel_draw(15-y,x,tile,flip))
3107 reset_draw = true;
3108 if(refl_flags & (1<<REFL_90CCW))
3109 if(__pixel_draw(y,15-x,tile,flip))
3110 reset_draw = true;
3111 }
3112 select_mode = tmp_sel_mode;
3113 }
3114
3115 if(reset_draw)
3116 drawing = 0;
3117 redraw=true;
3118 }
3119
3120 if(gui_mouse_b()==0)
3121 {
3122 bdown=false;
3123 drawing=0;
3124 }
3125
3126 temp_x=(gui_mouse_x()-zoomtile.x)/zoomtile.xscale;
3127 temp_y=(gui_mouse_y()-zoomtile.y)/zoomtile.yscale;
3128
3129 {
3130 tile_x=temp_x;
3131 tile_y=temp_y;
3132 redraw=true;
3133 }
3134
3135 const char *toolnames[t_max]=
3136 {
3137 "Pen\nDraw Single Pixels", "Fill\nCtrl", "Replace Color\nCtrl+Alt", "Grab Color\nAlt", "Move\nMove Selections", "Select Pixels", "Select Color"
3138 };
3139
3140 int32_t toolbtn = tool_btns.rectind(temp_mouse_x,temp_mouse_y);
3141 if(toolbtn > -1 && toolbtn < t_max)
3142 {
3143 int32_t column = toolbtn%tool_btns.w;
3144 int32_t row = toolbtn/tool_btns.w;
3145
3146 update_tooltip(temp_mouse_x,temp_mouse_y,tool_btns.x+(column*tool_btns.xscale),tool_btns.y+(row*tool_btns.yscale),tool_btns.xscale,tool_btns.yscale, toolnames[toolbtn]);
3147 redraw=true;
3148 }
3149 /* Highlight the hovered pixel? Eh, maybe too much?
3150 int32_t hov_pix = zoomtile.rectind(temp_mouse_x,temp_mouse_y);
3151 if(hov_pix > -1)
3152 {
3153 int32_t column = hov_pix%zoomtile.w;
3154 int32_t row = hov_pix/zoomtile.w;
3155
3156 update_tooltip(temp_mouse_x,temp_mouse_y,zoomtile.x+(column*zoomtile.xscale),zoomtile.y+(row*zoomtile.yscale),zoomtile.xscale,zoomtile.yscale, NULL);
3157 redraw=true;
3158 }*/
3159
3160 if(redraw)
3161 {
3162 draw_edit_scr(tile,flip,cs,oldtile, false);
3163 anim_hw_screen();
3164 }
3165 else
3166 {
3167 bool hs=has_selection();
3168
3169 if(hs)
3170 {
3171 zoomtile16(screen2,tile,zoomtile.x-1,zoomtile.y-1,cs,flip,zoomtile.xscale);
3172 blit(screen2, screen, zoomtile.x-1,zoomtile.y-1, zoomtile.x-1,zoomtile.y-1, (zoomtile.w*zoomtile.xscale)+1, (zoomtile.h*zoomtile.yscale)+1);
3173 anim_hw_screen();
3174 }
3175
3176 update_tool_cursor();
3177 }
3178 }
3179 while(!done);
3180
3181 unfloat_selection();
3182 clear_selection_grid();
3183
3184 while(gui_mouse_b()) ; // wait
3185
3186 if(done==1)
3187 {
3188 for(int32_t i=0; i<undocount; i++)
3189 {
3190 newtilebuf[tile].data[i]=oldtile[i];
3191 }
3192 }
3193 else
3194 {
3195 byte *buf = new byte[undocount];
3196
3197 // put back old tile
3198 for(int32_t i=0; i<undocount; i++)
3199 {
3200 buf[i] = newtilebuf[tile].data[i];
3201 newtilebuf[tile].data[i] = oldtile[i];
3202 }
3203
3204 // go
3205 go_tiles();
3206
3207 // replace old tile with new one again
3208 for(int32_t i=0; i<undocount; i++)
3209 {
3210 newtilebuf[tile].data[i] = buf[i];
3211 }
3212
3213 mark_save_dirty();
3214
3215 if(buf!=NULL)
3216 {
3217 delete[] buf;
3218 }
3219 }
3220
3221 MouseSprite::set(ZQM_NORMAL);
3222 register_blank_tiles();
3223 register_used_tiles();
3224 clear_tooltip();
3225 destroy_bitmap(selection_pattern);
3226 destroy_bitmap(selecting_pattern);
3227 destroy_bitmap(intersection_pattern);
3228 font = oldfont;
3229 popup_zqdialog_end();
3230 }
3231
3232 /* Grab Tile Code */
3233
3234 enum recolorState { rcNone, rc4Bit, rc8Bit };
3235
3236 BITMAP* original_imagebuf_bitmap=NULL;
3237 void *imagebuf=NULL;
3238 int32_t imagebuf_bitmap_scale=0;
3239 #define IMAGEBUF_SCALE (imagebuf_bitmap_scale > 0 ? imagebuf_bitmap_scale : 1.0 / -imagebuf_bitmap_scale)
3240 int32_t imagesize=0;
3241 int32_t tilecount=0;
3242 int32_t imagetype=0;
3243 int32_t imagex,imagey,selx,sely;
3244 int32_t bp=4,grabmode=16,romofs=0,romtilemode=0, romtilecols=8;
3245 bool nesmode=false;
3246 int32_t grabmask=0;
3247 recolorState recolor=rcNone;
3248 PALETTE imagepal;
3249
3250 /* bestfit_color:
3251 * Searches a palette for the color closest to the requested R, G, B value.
3252 */
3253 int32_t bestfit_cset_color(int32_t cs, int32_t r, int32_t g, int32_t b)
3254 {
3255 int32_t bestMatch = 0; // Color with the lowest total difference so far
3256 float bestTotalDiff = 100000; // Total difference between requested color and bestMatch
3257 float bestHighDiff = 100000; // Greatest difference of R, G, B between requested color and bestMatch
3258
3259 for(int32_t i = 0; i < CSET_SIZE; i++)
3260 {
3261 byte *rgbByte;
3262
3263 // This seems to be right...
3264 if(cs==2 || cs==3 || cs==4)
3265 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + (cs-2) + pdFULL) + i) * 3;
3266 else if(cs==9)
3267 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + 3 + pdFULL) + i) * 3;
3268 else if(cs==1&&get_qr(qr_CSET1_LEVEL))
3269 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + poNEWCSETS) + i) * 3;
3270 else if(cs==5&&get_qr(qr_CSET5_LEVEL))
3271 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + poNEWCSETS + 1) + i) * 3;
3272 else if(cs==7&&get_qr(qr_CSET7_LEVEL))
3273 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + poNEWCSETS + 2) + i) * 3;
3274 else if(cs==8&&get_qr(qr_CSET8_LEVEL))
3275 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + poNEWCSETS + 3) + i) * 3;
3276 else
3277 rgbByte = colordata + (CSET(cs)+i)*3;
3278
3279 int32_t dr=r-*rgbByte;
3280 int32_t dg=g-*(rgbByte+1);
3281 int32_t db=b-*(rgbByte+2);
3282
3283 // Track both the total color difference and the single greatest
3284 // difference of R, G, B. The idea is that it's better to have
3285 // two or three small differences than one big one.
3286 // The differences are multiplied by different numbers to account
3287 // for the differences in perceived brightness of the three colors.
3288 float totalDiff = sqrt(dr*dr*0.241 + dg*dg*0.691 + db*db*0.068);
3289 float highDiff = zc_max(zc_max(sqrt(dr*dr*0.241), sqrt(dg*dg*0.691)), sqrt(db*db*0.068));
3290
3291 // Perfect match? Just stop here.
3292 if(totalDiff==0)
3293 return i;
3294
3295 if(totalDiff < bestTotalDiff || // Best match so far?
3296 (totalDiff == bestTotalDiff && highDiff < bestHighDiff)) // Equally good match with lower high difference?
3297 {
3298 bestMatch=i;
3299 bestTotalDiff=totalDiff;
3300 bestHighDiff=highDiff;
3301 }
3302 }
3303
3304 return bestMatch;
3305 }
3306
3307 // Same as the above, but draws from all colors in CSets 0-11.
3308 int32_t bestfit_cset_color_8bit(int32_t r, int32_t g, int32_t b)
3309 {
3310 int32_t bestMatch = 0;
3311 float bestTotalDiff = 100000;
3312 float bestHighDiff = 100000;
3313
3314 for(int32_t i = 0; i < 192; i++) // 192 colors in CSets 0-11
3315 {
3316 byte *rgbByte;
3317
3318 int32_t cs=i>>4;
3319 if(cs==2 || cs==3 || cs==4)
3320 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + (cs-2) + pdFULL) + (i%16)) * 3;
3321 else if(cs==9)
3322 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + 3 + pdFULL) + (i%16)) * 3;
3323 else if(cs==1&&get_qr(qr_CSET1_LEVEL))
3324 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + poNEWCSETS) + (i%16)) * 3;
3325 else if(cs==5&&get_qr(qr_CSET5_LEVEL))
3326 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + poNEWCSETS + 1) + (i%16)) * 3;
3327 else if(cs==7&&get_qr(qr_CSET7_LEVEL))
3328 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + poNEWCSETS + 2) + (i%16)) * 3;
3329 else if(cs==8&&get_qr(qr_CSET8_LEVEL))
3330 rgbByte = colordata + (CSET((Map.CurrScr()->color) * pdLEVEL + poNEWCSETS + 3) + (i%16)) * 3;
3331 else
3332 rgbByte = colordata + i * 3;
3333
3334 int32_t dr=r-*rgbByte;
3335 int32_t dg=g-*(rgbByte+1);
3336 int32_t db=b-*(rgbByte+2);
3337
3338 float totalDiff = sqrt(dr*dr*0.241 + dg*dg*0.691 + db*db*0.068);
3339 float highDiff = zc_max(zc_max(sqrt(dr*dr*0.241), sqrt(dg*dg*0.691)), sqrt(db*db*0.068));
3340
3341 if(totalDiff==0) // Perfect match?
3342 return i;
3343
3344 if(totalDiff < bestTotalDiff || // Best match so far?
3345 (totalDiff == bestTotalDiff && highDiff < bestHighDiff)) // Equally good match with lower high difference?
3346 {
3347 bestMatch=i;
3348 bestTotalDiff=totalDiff;
3349 bestHighDiff=highDiff;
3350 }
3351 }
3352
3353 return bestMatch;
3354 }
3355
3356 byte cset_reduce_table[PAL_SIZE];
3357
3358 void calc_cset_reduce_table(PALETTE pal, int32_t cs)
3359 {
3360 for(int32_t i=0; i<PAL_SIZE; i++)
3361 {
3362 cset_reduce_table[i]=(bestfit_cset_color(cs, pal[i].r, pal[i].g, pal[i].b)&0x0F);
3363 }
3364 }
3365
3366 void calc_cset_reduce_table_8bit(PALETTE pal)
3367 {
3368 for(int32_t i=0; i<PAL_SIZE; i++)
3369 {
3370 cset_reduce_table[i]=bestfit_cset_color_8bit(pal[i].r, pal[i].g, pal[i].b);
3371 }
3372 }
3373
3374 void puttileROM(BITMAP *dest,int32_t x,int32_t y,byte *src,int32_t cs)
3375 {
3376 //storage space for the grabbed image
3377 byte buf[64];
3378 memset(buf,0,64);
3379 byte *oldsrc=src;
3380
3381 //for 8 lines in the source image...
3382 for(int32_t line=0; line<(nesmode?4:8); line++)
3383 {
3384 //bx is the pixel at the start of a line in the storage buffer
3385 int32_t bx=line<<(nesmode?4:3);
3386 //b is a byte in the source image (either an entire line in 1bp or the start of a line in others)
3387 byte b=src[(bp&1)?line:line<<1];
3388
3389 //fill the storage buffer with data from the source image
3390 for(int32_t i=7; i>=0; --i)
3391 {
3392 buf[bx+i] = (b&1)+(cs<<4);
3393 b>>=1;
3394 }
3395 }
3396
3397 ++src;
3398
3399 for(int32_t p=1; p<bp; p++)
3400 {
3401 for(int32_t line=0; line<(nesmode?4:8); line++)
3402 {
3403 int32_t bx=line<<(nesmode?4:3);
3404 byte b=src[(bp&1)?line:line<<1];
3405
3406 for(int32_t i=7; i>=0; --i)
3407 {
3408 if(nesmode)
3409 {
3410 buf[bx+8+i] = (b&1)+(cs<<4);
3411 }
3412 else
3413 {
3414 buf[bx+i] |= (b&1)<<p;
3415 }
3416
3417 b>>=1;
3418 }
3419 }
3420
3421 if(p&1)
3422 {
3423 src+=15;
3424 }
3425 else
3426 {
3427 ++src;
3428 }
3429 }
3430
3431
3432 if(nesmode)
3433 {
3434 src=oldsrc;
3435
3436 for(int32_t counter=0; counter<2; ++counter, ++src)
3437 {
3438 //for 8 lines in the source image...
3439 for(int32_t line=0; line<4; line++)
3440 {
3441 //bx is the pixel at the start of a line in the storage buffer
3442 int32_t bx=line<<4;
3443 //b is a byte in the source image (either an entire line in 1bp or the start of a line in others)
3444 byte b=src[(line+4)<<1];
3445
3446 //fill the storage buffer with data from the source image
3447 for(int32_t i=7; i>=0; --i)
3448 {
3449 // buf[bx+i] = (b&1)+(cs<<4);
3450 buf[bx+(counter<<3)+i] |= (b&1)<<1;
3451 b>>=1;
3452 }
3453 }
3454 }
3455 }
3456
3457 int32_t c=0;
3458
3459 switch(romtilemode)
3460 {
3461 case 0:
3462 case 1:
3463 case 2:
3464 for(int32_t j=0; j<8; j++)
3465 {
3466 for(int32_t i=0; i<8; i++)
3467 {
3468 putpixel(dest,x+i,y+j,buf[c++]);
3469 }
3470 }
3471
3472 break;
3473
3474 case 3:
3475 for(int32_t j=0; j<4; j++)
3476 {
3477 for(int32_t i=0; i<16; i++)
3478 {
3479 putpixel(dest,x+i,y+j,buf[c++]);
3480 }
3481 }
3482
3483 break;
3484 }
3485 }
3486
3487 const char *file_type[ftMAX]=
3488 {
3489 "None", "BIN", "BMP", "TIL", "ZGP", "QSU", "ZQT", "QST"
3490 };
3491
3492 void draw_grab_window()
3493 {
3494 int w = 640;
3495 int h = 480;
3496 int window_xofs=0;//(zq_screen_w-w-12)>>1;
3497 int window_yofs=0;//(zq_screen_h-h-25-6)>>1;
3498 jwin_draw_win(screen, window_xofs, window_yofs, w+6+6, h+25+6, FR_WIN);
3499 jwin_draw_frame(screen, window_xofs+4, window_yofs+23, w+2+2, h+2+2-(79*2), FR_DEEP);
3500
3501 FONT *oldfont = font;
3502 font = get_zc_font(font_lfont);
3503 jwin_draw_titlebar(screen, window_xofs+3, window_yofs+3, w+6, 18, "Grab Tile(s)", true);
3504 font=oldfont;
3505 }
3506
3507 void draw_grab_scr(int32_t tile, int32_t cs, byte *newtile,int32_t black, byte *newformat, BITMAP* screen3)
3508 {
3509
3510 int32_t yofs=0;
3511 //clear_to_color(screen2,bg);
3512 clear_bitmap(screen3);
3513 rectfill(screen2, 0, 0, 319, 159, black);
3514 rectfill(screen2,0,162,319,239,jwin_pal[jcBOX]);
3515 hline(screen2, 0, 160, 319, jwin_pal[jcMEDLT]);
3516 hline(screen2, 0, 161, 319, jwin_pal[jcLIGHT]);
3517 yofs=3;
3518
3519 // text_mode(-1);
3520 int32_t tileromcolumns=20;
3521
3522 switch(imagetype)
3523 {
3524 case ftBMP:
3525 if(recolor==rcNone)
3526 {
3527 blit((BITMAP*)imagebuf,screen2,imagex<<4,imagey<<4,0,0,320,160);
3528 }
3529 else
3530 {
3531 int32_t maxy=zc_min(160,((BITMAP*)imagebuf)->h);
3532 int32_t maxx=zc_min(320,((BITMAP*)imagebuf)->w);
3533
3534 for(int32_t y=0; y<maxy; y++)
3535 {
3536 if((imagey<<4)+y>=((BITMAP*)imagebuf)->h)
3537 {
3538 break;
3539 }
3540
3541 for(int32_t x=0; x<maxx; x++)
3542 {
3543 if((imagex<<4)+x>=((BITMAP*)imagebuf)->w)
3544 {
3545 break;
3546 }
3547
3548 if(recolor==rc8Bit)
3549 screen2->line[y][x]=cset_reduce_table[((BITMAP*)imagebuf)->line[(imagey<<4)+y][(imagex<<4)+x]];
3550 else
3551 screen2->line[y][x]=(cset_reduce_table[((BITMAP*)imagebuf)->line[(imagey<<4)+y][(imagex<<4)+x]])+(cs<<4);
3552 }
3553 }
3554 }
3555
3556 break;
3557
3558 case ftZGP:
3559 case ftQST:
3560 case ftZQT:
3561 case ftQSU:
3562 case ftTIL:
3563 {
3564 tiledata *hold = newtilebuf;
3565 newtilebuf = grabtilebuf;
3566 //fixme
3567 imagey = vbound(imagey, 0, MAXTILEROWS); //fixed -Z This can no longer crash if you scroll past the end of the tile pages. 6th June, 2020
3568 int32_t t=imagey*TILES_PER_ROW;
3569
3570 for(int32_t i=0; i<200; i++) // 10 rows, down to y=160
3571 {
3572 if(t <= tilecount)
3573 {
3574 puttile16(screen2,t,(i%TILES_PER_ROW)<<4,(i/TILES_PER_ROW)<<4,cs,0);
3575 }
3576
3577 ++t;
3578 }
3579
3580 newtilebuf = hold;
3581 //fixme
3582 }
3583 break;
3584
3585 case ftBIN:
3586 {
3587 int32_t ofs = (tileromcolumns*imagex + imagey) * 128*bp + romofs;
3588 byte *buf = (byte*)imagebuf;
3589
3590 switch(romtilemode)
3591 {
3592 case 0:
3593 for(int32_t y=0; y<160; y+=8)
3594 {
3595 for(int32_t x=0; ((x<128)&&(ofs<=imagesize-8*bp)); x+=8)
3596 {
3597 puttileROM(screen2,x,y,buf+ofs,cs);
3598 ofs+=8*bp;
3599 }
3600 }
3601
3602 for(int32_t y=0; y<160; y+=8)
3603 {
3604 for(int32_t x=0; ((x<128)&&(ofs<=imagesize-8*bp)); x+=8)
3605 {
3606 puttileROM(screen2,x+128,y,buf+ofs,cs);
3607 ofs+=8*bp;
3608 }
3609 }
3610
3611 break;
3612
3613 case 1:
3614 for(int32_t y=0; y<160; y+=16)
3615 {
3616 for(int32_t x=0; ((x<128)&&(ofs<=imagesize-8*bp)); x+=8)
3617 {
3618 puttileROM(screen2,x,y,buf+ofs,cs);
3619 ofs+=8*bp;
3620 puttileROM(screen2,x,y+8,buf+ofs,cs);
3621 ofs+=8*bp;
3622 }
3623 }
3624
3625 for(int32_t y=0; y<160; y+=16)
3626 {
3627 for(int32_t x=0; ((x<128)&&(ofs<=imagesize-8*bp)); x+=8)
3628 {
3629 puttileROM(screen2,x+128,y,buf+ofs,cs);
3630 ofs+=8*bp;
3631 puttileROM(screen2,x+128,y+8,buf+ofs,cs);
3632 ofs+=8*bp;
3633 }
3634 }
3635
3636 break;
3637
3638 case 2:
3639 for(int32_t y=0; y<160; y+=16)
3640 {
3641 for(int32_t x=0; ((x<128)&&(ofs<=imagesize-8*bp)); x+=16)
3642 {
3643 puttileROM(screen2,x,y,buf+ofs,cs);
3644 ofs+=8*bp;
3645 puttileROM(screen2,x+8,y,buf+ofs,cs);
3646 ofs+=8*bp;
3647 puttileROM(screen2,x,y+8,buf+ofs,cs);
3648 ofs+=8*bp;
3649 puttileROM(screen2,x+8,y+8,buf+ofs,cs);
3650 ofs+=8*bp;
3651 }
3652 }
3653
3654 for(int32_t y=0; y<160; y+=16)
3655 {
3656 for(int32_t x=0; ((x<128)&&(ofs<=imagesize-8*bp)); x+=16)
3657 {
3658 puttileROM(screen2,x+128,y,buf+ofs,cs);
3659 ofs+=8*bp;
3660 puttileROM(screen2,x+136,y,buf+ofs,cs);
3661 ofs+=8*bp;
3662 puttileROM(screen2,x+128,y+8,buf+ofs,cs);
3663 ofs+=8*bp;
3664 puttileROM(screen2,x+136,y+8,buf+ofs,cs);
3665 ofs+=8*bp;
3666 }
3667 }
3668
3669 break;
3670
3671 case 3:
3672 for(int32_t y=0; y<160; y+=16)
3673 {
3674 for(int32_t x=0; ((x<128)&&(ofs<=imagesize-8*bp)); x+=16)
3675 {
3676 puttileROM(screen2,x,y,buf+ofs,cs);
3677 ofs+=8*bp;
3678 puttileROM(screen2,x,y+4,buf+ofs,cs);
3679 ofs+=8*bp;
3680 puttileROM(screen2,x,y+8,buf+ofs,cs);
3681 ofs+=8*bp;
3682 puttileROM(screen2,x,y+12,buf+ofs,cs);
3683 ofs+=8*bp;
3684 }
3685 }
3686
3687 for(int32_t y=0; y<160; y+=16)
3688 {
3689 for(int32_t x=0; ((x<128)&&(ofs<=imagesize-8*bp)); x+=16)
3690 {
3691 puttileROM(screen2,x+128,y,buf+ofs,cs);
3692 ofs+=8*bp;
3693 puttileROM(screen2,x+128,y+4,buf+ofs,cs);
3694 ofs+=8*bp;
3695 puttileROM(screen2,x+128,y+8,buf+ofs,cs);
3696 ofs+=8*bp;
3697 puttileROM(screen2,x+128,y+12,buf+ofs,cs);
3698 ofs+=8*bp;
3699 }
3700 }
3701
3702 break;
3703 }
3704 }
3705 break;
3706 }
3707
3708 tiledata hold;
3709 bool holdblank = blank_tile_table[0];
3710
3711 if(is_valid_format(newtilebuf[0].format))
3712 {
3713 hold.format = newtilebuf[0].format;
3714 hold.data = (byte *)malloc(tilesize(hold.format));
3715 memcpy(hold.data, newtilebuf[0].data, tilesize(hold.format));
3716 }
3717 else
3718 {
3719 hold.format=tfInvalid;
3720 hold.data=NULL;
3721 }
3722
3723 newtilebuf[0].format=newformat[0];
3724 blank_tile_table[0] = false;
3725
3726 if(newtilebuf[0].data!=NULL)
3727 {
3728 free(newtilebuf[0].data);
3729 }
3730
3731 if(is_valid_format(newtilebuf[0].format))
3732 {
3733 newtilebuf[0].data = (byte *)malloc(tilesize(newtilebuf[0].format));
3734
3735 for(int32_t i=0; i<tilesize(newtilebuf[0].format); i++)
3736 {
3737 newtilebuf[0].data[i]=newtile[i];
3738 }
3739 }
3740 else
3741 {
3742 newtilebuf[0].data=NULL;
3743 }
3744
3745 puttile16(screen2,0,208,168+yofs,cs,0);
3746 overtile16(screen2,0,232,168+yofs,cs,0);
3747 newtilebuf[0].format=hold.format;
3748 blank_tile_table[0] = holdblank;
3749
3750 if(newtilebuf[0].data!=NULL)
3751 {
3752 free(newtilebuf[0].data);
3753 }
3754
3755 if(is_valid_format(newtilebuf[0].format))
3756 {
3757 newtilebuf[0].data = (byte *)malloc(tilesize(newtilebuf[0].format));
3758
3759 for(int32_t i=0; i<256; i++)
3760 {
3761 newtilebuf[0].data[i]=hold.data[i];
3762 }
3763 }
3764 else
3765 {
3766 newtilebuf[0].data=NULL;
3767 }
3768
3769 if(hold.data!=NULL)
3770 {
3771 free(hold.data);
3772 }
3773
3774 puttile16(screen2,tile,208,192+yofs,cs,0);
3775 overtile16(screen2,tile,232,192+yofs,cs,0);
3776
3777 rectfill(screen2,184,168+yofs,191,175+yofs,grabmask&1?vc(12):vc(7));
3778 rectfill(screen2,192,168+yofs,199,175+yofs,grabmask&2?vc(12):vc(7));
3779 rectfill(screen2,184,176+yofs,191,183+yofs,grabmask&4?vc(12):vc(7));
3780 rectfill(screen2,192,176+yofs,199,183+yofs,grabmask&8?vc(12):vc(7));
3781
3782 // rect(screen2,183,167,200,184,dvc(7*2));
3783 // rect(screen2,207,167,224,184,dvc(7*2));
3784 // rect(screen2,231,167,248,184,dvc(7*2));
3785 // rect(screen2,207,191,224,208,dvc(7*2));
3786 // rect(screen2,231,191,248,208,dvc(7*2));
3787
3788 /*
3789 rect(screen2,183,167,200,184,vc(14));
3790 rect(screen2,207,167,224,184,vc(14));
3791 rect(screen2,231,167,248,184,vc(14));
3792 rect(screen2,207,191,224,208,vc(14));
3793 rect(screen2,231,191,248,208,vc(14));
3794 */
3795 jwin_draw_frame(screen2,182,166+yofs,20,20,FR_DEEP);
3796 jwin_draw_frame(screen2,206,166+yofs,20,20,FR_DEEP);
3797 jwin_draw_frame(screen2,230,166+yofs,20,20,FR_DEEP);
3798 jwin_draw_frame(screen2,206,190+yofs,20,20,FR_DEEP);
3799 jwin_draw_frame(screen2,230,190+yofs,20,20,FR_DEEP);
3800 int32_t screen_xofs=6;
3801 int32_t screen_yofs=25;
3802 int winh = 511;
3803 int32_t mul = 2;
3804
3805 yofs = 0;
3806
3807 stretch_blit(screen2,screen3,0,0,320,240,0,0,640,480);
3808
3809 // Suspend the current font while draw_text_button does its work
3810 FONT* oldfont = font;
3811
3812 font = get_zc_font(font_lfont_l);
3813
3814 int txt_x = 4;
3815 int rbtn_x = 512, lbtn_x = 236;
3816 int max_fpath_wid = rbtn_x-2-txt_x;
3817 int max_fpath_wid2 = max_fpath_wid-text_length(font,"... ");
3818 // Interface
3819 switch(imagetype)
3820 {
3821 case 0:
3822 textprintf_ex(screen3,font,txt_x,(216+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"%s",imgstr[imagetype]);
3823 break;
3824
3825 case ftBMP:
3826 {
3827 std::string text = fmt::format("{} {}x{}, {:.2g}x zoom with , and .", imgstr[imagetype], original_imagebuf_bitmap->w, original_imagebuf_bitmap->h, IMAGEBUF_SCALE);
3828 int text_x = txt_x;
3829 int text_y = (216 + yofs) * mul;
3830 // TODO: can almost use this, but drawing is offset. prob cuz drawing to a different bitmap than the normal screen bitmap? idk
3831 // int text_w = text_length(font, text.c_str());
3832 // int text_h = text_height(font);
3833 // static int grab_scale_tooltip_id = ttip_register_id();
3834 // ttip_install(grab_scale_tooltip_id, "zoom with , and .", text_x, text_y, text_w, text_h, text_x, text_y - 40);
3835 textprintf_ex(screen3, font, text_x, text_y, jwin_pal[jcTEXTFG], jwin_pal[jcBOX], "%s", text.c_str());
3836
3837 draw_text_button(screen3,lbtn_x,(192+yofs)*mul,int32_t(61*(1.5)),int32_t(20*(1.5)),"Recolor",vc(1),vc(14),0,true);
3838 break;
3839 }
3840
3841 case ftZGP:
3842 case ftQST:
3843 case ftZQT:
3844 case ftQSU:
3845 case ftTIL:
3846 case ftBIN:
3847 textprintf_ex(screen3,get_zc_font(font_lfont_l),txt_x,(216+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"%s %d KB",imgstr[imagetype],imagesize>>10);
3848 break;
3849 }
3850
3851 textprintf_ex(screen3,font,txt_x,(168+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"sel: %d %d",selx,sely);
3852 textprintf_ex(screen3,font,txt_x,(176+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"pos: %d %d",imagex,imagey);
3853
3854 if(bp==8)
3855 textprintf_ex(screen3,font,txt_x,(192+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"8-bit");
3856 else
3857 textprintf_ex(screen3,font,txt_x,(192+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"cset: %d",cs);
3858 textprintf_ex(screen3,font,txt_x,(200+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"step: %d",grabmode);
3859
3860 if(imagetype==ftBIN)
3861 {
3862 textprintf_ex(screen3,font,104*mul,(192+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"bp: %d%s",bp,nesmode?" (NES)":"");
3863 textprintf_ex(screen3,font,104*mul,(200+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"ofs: %Xh",romofs);
3864 textprintf_ex(screen3,font,104*mul,(208+yofs)*mul,jwin_pal[jcTEXTFG],jwin_pal[jcBOX],"m: %d",romtilemode);
3865 }
3866
3867 int fpath_y = (224+yofs)*mul;
3868 if(text_length(font,imagepath) <= max_fpath_wid)
3869 textout_ex(screen3,font,imagepath,txt_x,fpath_y,jwin_pal[jcTEXTFG],jwin_pal[jcBOX]);
3870 else
3871 {
3872 char buf[2052] = {0};
3873 strncpy(buf,imagepath,2048);
3874 int len = strlen(buf);
3875 char *ptr = buf;
3876 char *endptr = buf+len;
3877 char *it = endptr;
3878 int tmpy = fpath_y;
3879 int tmph = text_height(font)+1;
3880 while(true)
3881 {
3882 if(tmpy+tmph > (winh-2))
3883 break; //Out of space!
3884 char c = *it;
3885 bool end = !c;
3886 *it = 0;
3887 int newlen = text_length(font,ptr);
3888 if(newlen <= (end ? max_fpath_wid : max_fpath_wid2))
3889 {
3890 if(end) //No stored character, string ended
3891 {
3892 textout_ex(screen3,font,ptr,txt_x,tmpy,jwin_pal[jcTEXTFG],jwin_pal[jcBOX]);
3893 break;
3894 }
3895 char t[5];
3896 t[0] = c;
3897 for(int q = 1; q < 5; ++q)
3898 t[q] = it[q];
3899 strcpy(it,"...");
3900 textout_ex(screen3,font,ptr,txt_x,tmpy,jwin_pal[jcTEXTFG],jwin_pal[jcBOX]);
3901 for(int q = 0; q < 5; ++q)
3902 it[q] = t[q];
3903 tmpy += tmph;
3904 ptr = it;
3905 it = endptr;
3906 }
3907 else
3908 {
3909 *it = c;
3910 --it;
3911 }
3912 }
3913 }
3914 draw_text_button(screen3,rbtn_x,(168+yofs)*mul,int32_t(61*(1.5)),int32_t(20*(1.5)),"OK",vc(1),vc(14),0,true);
3915 draw_text_button(screen3,rbtn_x,(192+yofs)*mul,int32_t(61*(1.5)),int32_t(20*(1.5)),"Cancel",vc(1),vc(14),0,true);
3916 draw_text_button(screen3,rbtn_x,(216+yofs)*mul,int32_t(61*(1.5)),int32_t(20*(1.5)),"File",vc(1),vc(14),0,true);
3917 draw_text_button(screen3,lbtn_x,(166+yofs)*mul,int32_t(61*(1.5)),int32_t(20*(1.5)),"Leech",vc(1),vc(14),0,true);
3918
3919 font = oldfont;
3920 }
3921
3922 COLOR_MAP imagepal_table;
3923
3924
3925 extern void return_RAMpal_color(AL_CONST PALETTE pal, int32_t x, int32_t y, RGB *rgb)
3926 {
3927 //these are here to bypass compiler warnings about unused arguments
3928 x=x;
3929
3930 rgb->r = pal[y].r;
3931 rgb->g = pal[y].g;
3932 rgb->b = pal[y].b;
3933 }
3934
3935
3936 void load_imagebuf()
3937 {
3938 PACKFILE *f;
3939 //cache QRS
3940 //byte cached_rules[QUESTRULES_NEW_SIZE] = { 0 };
3941 //for ( int32_t q = 0; q < QUESTRULES_NEW_SIZE; ++q )
3942 // {
3943 // cached_rules[q] = quest_rules[q];
3944 // }
3945 bool compressed=false;
3946 bool encrypted=false;
3947 tiledata *hold=newtilebuf;
3948 zquestheader tempheader{};
3949
3950 if(imagebuf)
3951 {
3952 switch(imagetype)
3953 {
3954 case ftBMP:
3955 if (original_imagebuf_bitmap != imagebuf)
3956 destroy_bitmap((BITMAP*)imagebuf);
3957 destroy_bitmap(original_imagebuf_bitmap);
3958 break;
3959
3960 case ftZGP:
3961 case ftQST:
3962 case ftZQT:
3963 case ftQSU:
3964 case ftTIL:
3965 clear_tiles(grabtilebuf);
3966 break;
3967
3968 case ftBIN:
3969 free(imagebuf);
3970 break;
3971 }
3972
3973 imagebuf=NULL;
3974 original_imagebuf_bitmap=NULL;
3975 }
3976
3977 selx=sely=romofs=0;
3978 bp=4;
3979 imagetype=filetype(imagepath);
3980
3981 dword section_id;
3982 word section_version;
3983
3984 switch(imagetype)
3985 {
3986 case ftBMP:
3987 packfile_password("");
3988 memset(imagepal, 0, sizeof(PALETTE));
3989 original_imagebuf_bitmap = load_bitmap(imagepath,imagepal);
3990 imagesize = file_size_ex_password(imagepath,"");
3991 tilecount=0;
3992
3993 RGB_MAP tmp_rgb_table;
3994 create_rgb_table(&tmp_rgb_table, imagepal, NULL);
3995 rgb_map = &tmp_rgb_table;
3996 create_color_table(&imagepal_table, RAMpal, return_RAMpal_color, NULL);
3997
3998 if(!original_imagebuf_bitmap)
3999 {
4000 imagetype=0;
4001 }
4002 else
4003 {
4004 imagebuf = original_imagebuf_bitmap;
4005 imagebuf_bitmap_scale = 1;
4006 }
4007
4008 break;
4009
4010 case ftBIN:
4011 packfile_password("");
4012 imagesize = file_size_ex_password(imagepath, "");
4013 tilecount=0;
4014
4015 if(imagesize)
4016 {
4017 imagebuf = malloc(imagesize);
4018
4019 if(!readfile(imagepath,imagebuf,imagesize))
4020 {
4021 free(imagebuf);
4022 imagesize=0;
4023 imagetype=0;
4024 }
4025 }
4026
4027 break;
4028
4029 case ftTIL:
4030 packfile_password("");
4031 imagesize = file_size_ex_password(imagepath,"");
4032 f = pack_fopen_password(imagepath,F_READ,"");
4033
4034 if(!f)
4035 {
4036 goto error;
4037 }
4038
4039 if(!p_mgetl(&section_id,f))
4040 {
4041 goto error;
4042 }
4043
4044 if(section_id==ID_TILES)
4045 {
4046 if(readtiles(f, grabtilebuf, NULL, ZELDA_VERSION, VERSION_BUILD, 0, NEWMAXTILES, false)==0)
4047 {
4048 goto error;
4049 }
4050 }
4051
4052 error:
4053 pack_fclose(f);
4054 tilecount=count_tiles(grabtilebuf);
4055 break;
4056
4057 case ftZGP:
4058 packfile_password("");
4059 imagesize = file_size_ex_password(imagepath, "");
4060 f=pack_fopen_password(imagepath,F_READ,"");
4061
4062 if(!f)
4063 {
4064 goto error2;
4065 }
4066
4067 if(!p_mgetl(&section_id,f))
4068 {
4069 goto error2;
4070 }
4071
4072 if(section_id!=ID_GRAPHICSPACK)
4073 {
4074 goto error2;
4075 }
4076
4077 //section version info
4078 if(!p_igetw(&section_version,f))
4079 {
4080 goto error2;
4081 }
4082
4083 if(!read_deprecated_section_cversion(f))
4084 {
4085 goto error2;
4086 }
4087
4088 //tiles
4089 if(!p_mgetl(&section_id,f))
4090 {
4091 goto error2;
4092 }
4093
4094 if(section_id==ID_TILES)
4095 {
4096 if(readtiles(f, grabtilebuf, NULL, ZELDA_VERSION, VERSION_BUILD, 0, NEWMAXTILES, false)!=0)
4097 {
4098 goto error2;
4099 }
4100 }
4101
4102 error2:
4103 pack_fclose(f);
4104 tilecount=count_tiles(grabtilebuf);
4105 break;
4106
4107 case ftQST:
4108 encrypted=true;
4109 case ftZQT:
4110 compressed=true;
4111 case ftQSU:
4112 packfile_password("");
4113 imagesize = file_size_ex_password(imagepath, encrypted ? datapwd : "");
4114 newtilebuf=grabtilebuf;
4115 byte skip_flags[4];
4116
4117 for(int32_t i=0; i<skip_max; ++i)
4118 {
4119 set_bit(skip_flags,i,1);
4120 }
4121
4122 set_bit(skip_flags,skip_tiles,0);
4123 set_bit(skip_flags,skip_header,0);
4124 int ret = loadquest(imagepath,&tempheader,&QMisc,customtunes,true,skip_flags);
4125 if (ret)
4126 {
4127 imagetype=0;
4128 imagesize=0;
4129 clear_tiles(grabtilebuf);
4130 chop_path(imagepath);
4131 }
4132
4133 if (!ret && encrypted && compressed)
4134 {
4135 if(quest_access(imagepath, &tempheader) != 1)
4136 {
4137 imagetype=0;
4138 imagesize=0;
4139 clear_tiles(grabtilebuf);
4140 chop_path(imagepath);
4141 }
4142 }
4143
4144 //setPackfilePassword(NULL);
4145 newtilebuf=hold;
4146 tilecount=count_tiles(grabtilebuf);
4147 break;
4148 }
4149
4150 rgb_map = zq_rgb_table;
4151 //restore cashed QRs / rules
4152
4153 //for ( int32_t q = 0; q < QUESTRULES_NEW_SIZE; ++q )
4154 // {
4155 // quest_rules[q] = cached_rules[q];
4156 // }
4157 }
4158
4159 static char bitstrbuf[32];
4160 bool leeching_from_tiles=false;
4161
4162 const char *bitlist(int32_t index, int32_t *list_size)
4163 {
4164 int32_t imported=2;
4165
4166 if(index>=0)
4167 {
4168 bound(index,0,leeching_from_tiles?2:1);
4169
4170 if(index==imported)
4171 {
4172 sprintf(bitstrbuf,"Imported");
4173 }
4174 else
4175 {
4176 sprintf(bitstrbuf,"%d",4<<index);
4177 }
4178
4179 return bitstrbuf;
4180 }
4181
4182 *list_size=leeching_from_tiles?3:2;
4183 return NULL;
4184 }
4185
4186 12 static ListData bit_list(bitlist, &font);
4187
4188 static DIALOG leech_dlg[] =
4189 {
4190 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) */
4191 12 { jwin_win_proc, 8, 20-4, 303+1, 216-42+1, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *) "Leech Options", NULL, NULL },
4192 12 { d_timer_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
4193 // 2
4194 12 { jwin_button_proc, 180, 210-42-4, 61, 21, vc(14), vc(1), 27, D_EXIT, 0, 0, (void *) "Cancel", NULL, NULL },
4195 12 { jwin_button_proc, 80, 210-42-4, 61, 21, vc(14), vc(1), 13, D_EXIT, 0, 0, (void *) "OK", NULL, NULL },
4196 12 { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 0, 0, KEY_F1, 0, (void *) onHelp, NULL, NULL },
4197 // 5
4198 12 { jwin_text_proc, 14, 49-4, 176, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "Update Status Every: ", NULL, NULL },
4199 12 { jwin_edit_proc, 114, 45-4, 36, 16, vc(12), vc(1), 0, 0, 5, 0, NULL, NULL, NULL },
4200 12 { jwin_radio_proc, 155, 49-4, 64+1, 8+1, vc(14), vc(1), 0, 0, 0, 0, (void *) "Tiles", NULL, NULL },
4201 12 { jwin_radio_proc, 200, 49-4, 64+1, 8+1, vc(14), vc(1), 0, 0, 0, 0, (void *) "Seconds", NULL, NULL },
4202 //9
4203 12 { jwin_frame_proc, 14, 63-2, 176+70, 50+30, jwin_pal[jcBOXFG], jwin_pal[jcBOX], 0, 0, FR_ETCHED, 0, NULL, NULL, NULL },
4204 12 { jwin_text_proc, 14+8, 60-2, 80, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) " Duplicates ", NULL, NULL },
4205
4206 12 { jwin_check_proc, 20, 70, 168, 8+1, vc(15), vc(1), 0, 0, 1, 0, (void *) "Only check new tiles", NULL, NULL },
4207 12 { jwin_text_proc, 20, 90, 72, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "Normal:", NULL, NULL },
4208 12 { jwin_text_proc, 20, 100, 72, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "Horizontal Flip:", NULL, NULL },
4209 12 { jwin_text_proc, 20, 110, 72, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "Vertical Flip:", NULL, NULL },
4210 12 { jwin_text_proc, 20, 120, 72, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "Horizontal/Vertical Flip:", NULL, NULL },
4211 //16
4212 12 { jwin_radio_proc, 144, 90, 64+1, 8+1, vc(14), vc(1), 0, 0, 1, 0, NULL, NULL, NULL },
4213 12 { jwin_radio_proc, 184, 90, 56+1, 8+1, vc(14), vc(1), 0, 0, 1, 0, NULL, NULL, NULL },
4214 12 { jwin_radio_proc, 224, 90, 72+1, 8+1, vc(14), vc(1), 0, 0, 1, 0, NULL, NULL, NULL },
4215
4216 12 { jwin_radio_proc, 144, 100, 64+1, 8+1, vc(14), vc(1), 0, 0, 2, 0, NULL, NULL, NULL },
4217 12 { jwin_radio_proc, 184, 100, 56+1, 8+1, vc(14), vc(1), 0, 0, 2, 0, NULL, NULL, NULL },
4218 12 { jwin_radio_proc, 224, 100, 72+1, 8+1, vc(14), vc(1), 0, 0, 2, 0, NULL, NULL, NULL },
4219
4220 12 { jwin_radio_proc, 144, 110, 64+1, 8+1, vc(14), vc(1), 0, 0, 3, 0, NULL, NULL, NULL },
4221 12 { jwin_radio_proc, 184, 110, 56+1, 8+1, vc(14), vc(1), 0, 0, 3, 0, NULL, NULL, NULL },
4222 12 { jwin_radio_proc, 224, 110, 72+1, 8+1, vc(14), vc(1), 0, 0, 3, 0, NULL, NULL, NULL },
4223
4224 12 { jwin_radio_proc, 144, 120, 64+1, 8+1, vc(14), vc(1), 0, 0, 4, 0, NULL, NULL, NULL },
4225 12 { jwin_radio_proc, 184, 120, 56+1, 8+1, vc(14), vc(1), 0, 0, 4, 0, NULL, NULL, NULL },
4226 12 { jwin_radio_proc, 224, 120, 72+1, 8+1, vc(14), vc(1), 0, 0, 4, 0, NULL, NULL, NULL },
4227
4228 12 { jwin_ctext_proc, 144+4, 80, 64+1, 8+1, vc(14), vc(1), 0, 0, 0, 0, (void *) "Ignore", NULL, NULL },
4229 12 { jwin_ctext_proc, 184+4, 80, 56+1, 8+1, vc(14), vc(1), 0, 0, 0, 0, (void *) "Check", NULL, NULL },
4230 12 { jwin_ctext_proc, 224+4, 80, 72+1, 8+1, vc(14), vc(1), 0, 0, 0, 0, (void *) "Discard", NULL, NULL },
4231 12 { jwin_droplist_proc, 76, 145, 80, 16, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, 0, 1, 0, (void *) &bit_list, NULL, NULL },
4232 12 { jwin_text_proc, 14, 149, 60, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "Color Depth: ", NULL, NULL },
4233 12 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
4234 };
4235
4236 bool leech_tiles(tiledata *dest,int32_t start,int32_t cs)
4237 {
4238 bool shift=true; // fix this!
4239 int32_t cst=0;
4240 int32_t currtile=start;
4241 int32_t height=0, width=0;
4242 byte *testtile = new byte[tilesize(tf32Bit)];
4243 byte imported_format=0;
4244 char updatestring[6];
4245 bool canadd;
4246 bool temp_canadd;
4247 bool duplicate;
4248 int32_t total_duplicates_found=0, total_duplicates_discarded=0;
4249 int32_t duplicates_found[4]= //, duplicates_discarded[4]={0,0,0,0};
4250 {
4251 0,0,0,0
4252 };
4253 BITMAP *status;
4254 status = create_bitmap_ex(8,240,140);
4255 clear_bitmap(status);
4256 sprintf(updatestring, "%d", LeechUpdate);
4257 leech_dlg[0].dp2=get_zc_font(font_lfont);
4258 leech_dlg[6].dp=updatestring;
4259
4260 leech_dlg[10].flags=(OnlyCheckNewTilesForDuplicates!=0) ? D_SELECTED : 0;
4261
4262 for(int32_t i=0; i<2; i++)
4263 {
4264 leech_dlg[i+7].flags=0;
4265 }
4266
4267 leech_dlg[7+((LeechUpdateTiles==0) ? 1 : 0)].flags=D_SELECTED;
4268
4269 for(int32_t i=0; i<12; i++)
4270 {
4271 leech_dlg[i+16].flags=0;
4272 }
4273
4274 for(int32_t i=0; i<4; i++)
4275 {
4276 leech_dlg[(DuplicateAction[i])+16+(i*3)].flags=D_SELECTED;
4277 }
4278
4279 leech_dlg[31].d1=0;
4280
4281 large_dialog(leech_dlg);
4282
4283 int32_t ret = do_zqdialog(leech_dlg,3);
4284
4285 if(ret==2)
4286 {
4287 delete[] testtile;
4288 return false;
4289 }
4290
4291 int32_t cdepth=leech_dlg[31].d1+1;
4292 int32_t newformat=0;
4293 auto lu = atoi(updatestring);
4294 auto lut = (leech_dlg[7].flags&D_SELECTED)?1:0;
4295 if(LeechUpdate!=lu)
4296 {
4297 LeechUpdate=lu;
4298 zc_set_config("zquest","leech_update",LeechUpdate);
4299 }
4300 if(LeechUpdateTiles!=lut)
4301 {
4302 LeechUpdateTiles=lut;
4303 zc_set_config("zquest","leech_update_tiles",LeechUpdateTiles);
4304 }
4305
4306 int32_t old_dupe[4];
4307 for(int32_t j=0; j<4; j++)
4308 {
4309 old_dupe[j] = DuplicateAction[j];
4310 for(int32_t i=0; i<3; i++)
4311 {
4312 if(leech_dlg[i+16+(j*3)].flags&D_SELECTED)
4313 {
4314 DuplicateAction[j]=i;
4315 }
4316 }
4317 }
4318 if(old_dupe[0] != DuplicateAction[0])
4319 zc_set_config("zquest","normal_duplicate_action",DuplicateAction[0]);
4320 if(old_dupe[1] != DuplicateAction[1])
4321 zc_set_config("zquest","horizontal_duplicate_action",DuplicateAction[1]);
4322 if(old_dupe[2] != DuplicateAction[2])
4323 zc_set_config("zquest","vertical_duplicate_action",DuplicateAction[2]);
4324 if(old_dupe[3] != DuplicateAction[3])
4325 zc_set_config("zquest","both_duplicate_action",DuplicateAction[3]);
4326
4327 auto ocntfd = leech_dlg[10].flags&D_SELECTED?1:0;
4328 if(OnlyCheckNewTilesForDuplicates!=ocntfd)
4329 {
4330 OnlyCheckNewTilesForDuplicates=ocntfd;
4331 zc_set_config("zquest","only_check_new_tiles_for_duplicates",ocntfd);
4332 }
4333
4334 leeching_from_tiles=false;
4335
4336 switch(imagetype)
4337 {
4338 case ftBIN:
4339 width=imagesize/128;
4340 height=1;
4341 break;
4342
4343 case ftZGP:
4344 case ftQST:
4345 case ftZQT:
4346 case ftQSU:
4347 case ftTIL:
4348 leeching_from_tiles=true;
4349 width=count_tiles(grabtilebuf);
4350 height=1;
4351 break;
4352
4353 case ftBMP:
4354 width=((((BITMAP*)imagebuf)->w)+15)/16;
4355 height=((((BITMAP*)imagebuf)->h)+15)/16;
4356 break;
4357 }
4358
4359 if(currtile+(width*height)>NEWMAXTILES)
4360 {
4361 if(jwin_alert("Confirm Truncation","Too many tiles.","Truncation may occur.",NULL,"&OK","&Cancel",'o','c',get_zc_font(font_lfont))==2)
4362 {
4363 delete[] testtile;
4364 return false;
4365 }
4366 }
4367
4368 go_tiles();
4369 mark_save_dirty();
4370
4371 for(int32_t ty=0; ty<height; ty++) //for every row
4372 {
4373 for(int32_t tx=0; tx<width; tx++) //for every column (tile)
4374 {
4375 if((((ty*width)+tx)%zc_max(LeechUpdate, 1))==0) //update status
4376 {
4377 FONT *oldfont = font;
4378 static BITMAP *tbar = create_bitmap_ex(8,240-6, 18);
4379 static bool created_tbar=false;
4380 jwin_draw_win(status, 0, 0, 240, 140, FR_WIN);
4381
4382 if(created_tbar)
4383 {
4384 blit(tbar, status, 0, 0, 3, 3, 240-6, 18);
4385 }
4386 else
4387 {
4388 font = get_zc_font(font_lfont);
4389 jwin_draw_titlebar(tbar, 0, 0, 240-6, 18, "Leech Status", false);
4390 font = oldfont;
4391 created_tbar=true;
4392 blit(tbar, status, 0, 0, 3, 3, 320-6, 18);
4393 }
4394
4395 textprintf_centre_ex(status,font,120,24,jwin_pal[jcTEXTFG],-1,"Checking %d of %d",((ty*width)+tx), (width*height));
4396 textprintf_centre_ex(status,font,120,34,jwin_pal[jcTEXTFG],-1,"%d tiles imported",currtile-start);
4397 jwin_draw_frame(status, 40, 49, 160, 70, FR_ETCHED);
4398 textprintf_centre_ex(status,font,120,46,jwin_pal[jcTEXTFG],jwin_pal[jcBOX]," Duplicates ");
4399 textprintf_centre_ex(status,font,120,56,jwin_pal[jcTEXTFG],-1,"%d/%d found/discarded",total_duplicates_found, total_duplicates_discarded);
4400 textprintf_centre_ex(status,font,120,76,jwin_pal[jcTEXTFG],-1,"%d normal %s",duplicates_found[0],((DuplicateAction[0]<2)?"found":"discarded"));
4401 textprintf_centre_ex(status,font,120,86,jwin_pal[jcTEXTFG],-1,"%d flipped (h) %s",duplicates_found[1],((DuplicateAction[1]<2)?"found":"discarded"));
4402 textprintf_centre_ex(status,font,120,96,jwin_pal[jcTEXTFG],-1,"%d flipped (v) %s",duplicates_found[2],((DuplicateAction[2]<2)?"found":"discarded"));
4403 textprintf_centre_ex(status,font,120,106,jwin_pal[jcTEXTFG],-1,"%d flipped (hv) %s",duplicates_found[3],((DuplicateAction[3]<2)?"found":"discarded"));
4404 textprintf_centre_ex(status,font,120,128,jwin_pal[jcTEXTFG],-1,"Press any key to stop.");
4405 blit(status,screen,0, 0, 40, 20, 240, 140);
4406 }
4407
4408 canadd=true;
4409
4410 if(currtile>=NEWMAXTILES) //if we've maxed out on our tiles...
4411 {
4412 delete[] testtile;
4413 return true;
4414 }
4415
4416 switch(imagetype)
4417 {
4418 case ftBIN:
4419 break;
4420
4421 case ftZGP:
4422 case ftQST:
4423 case ftZQT:
4424 case ftQSU:
4425 case ftTIL:
4426 memset(testtile, 0, tilesize(tf32Bit));
4427 imported_format=grabtilebuf[tx].format;
4428
4429 switch(cdepth)
4430 {
4431 case 1: //4-bit
4432 newformat=tf4Bit;
4433
4434 switch(imported_format)
4435 {
4436 case tf4Bit:
4437 case tf8Bit:
4438 for(int32_t y=0; y<16; y++) //snag a tile
4439 {
4440 for(int32_t x=0; x<16; x+=2)
4441 {
4442 testtile[(y*8)+(x/2)]=
4443 (grabtilebuf[tx].data[y*16+x]&15)+
4444 ((grabtilebuf[tx].data[y*16+x+1]&15)<<4);
4445 }
4446 }
4447
4448 break;
4449 }
4450
4451 break;
4452
4453 case 2: //8-bit
4454 newformat=tf8Bit;
4455
4456 switch(imported_format)
4457 {
4458 case tf4Bit:
4459 unpack_tile(grabtilebuf, tx, 0, true);
4460 cst = cs&15;
4461 cst <<= CSET_SHFT;
4462
4463 for(int32_t i=0; i<256; i++)
4464 {
4465 if(!shift||unpackbuf[i]!=0)
4466 {
4467 unpackbuf[i]+=cst;
4468 }
4469 }
4470
4471 pack_tiledata(testtile, unpackbuf, tf8Bit);
4472 break;
4473
4474 case tf8Bit:
4475 memcpy(testtile,grabtilebuf[tx].data,tilesize(imported_format));
4476 break;
4477 }
4478
4479 break;
4480
4481 case 3: //original tile's bit depth
4482 newformat=imported_format;
4483 memcpy(testtile,grabtilebuf[tx].data,tilesize(imported_format));
4484 break;
4485 }
4486
4487 break;
4488
4489 case ftBMP:
4490 newformat=cdepth;
4491
4492 for(int32_t y=0; y<16; y++) //snag a tile
4493 {
4494 for(int32_t x=0; x<16; x+=2)
4495 {
4496 testtile[(y*16)+x]=getpixel(((BITMAP*)imagebuf),(tx*16)+x,(ty*16)+y);
4497 testtile[(y*16)+x+1]=getpixel(((BITMAP*)imagebuf),(tx*16)+x+1,(ty*16)+y);
4498 }
4499 }
4500
4501 break;
4502 }
4503
4504 if(DuplicateAction[0]+DuplicateAction[1]+DuplicateAction[2]+DuplicateAction[3]>0)
4505 {
4506 temp_canadd=true;
4507
4508 //check all tiles before this one
4509 for(int32_t checktile=((OnlyCheckNewTilesForDuplicates!=0)?start:0); ((temp_canadd==true)&&(checktile<currtile)); checktile++)
4510 {
4511 for(int32_t flipping=0; ((temp_canadd==true)&&(flipping<4)); ++flipping)
4512 {
4513 if(DuplicateAction[flipping]>0)
4514 {
4515 if(keypressed())
4516 {
4517 delete[] testtile;
4518 return true;
4519 }
4520
4521 duplicate=(newformat==imported_format);
4522
4523 if(duplicate)
4524 {
4525 switch(flipping)
4526 {
4527 case 0: //normal
4528 if(dest[checktile].data!=NULL)
4529 {
4530 for(int32_t y=0; ((duplicate==true)&&(y<16)); y++)
4531 {
4532 for(int32_t x=0; ((duplicate==true)&&(x<16)); x+=3-newformat)
4533 {
4534 // if ((dest[(checktile*128)+(y*8)+(x/2)])!=(testtile[(y*8)+(x/2)]))
4535 if((dest[checktile].data[(y*8*newformat)+(x/(3-newformat))])!=testtile[(y*16)+x])
4536 {
4537 duplicate=false;
4538 }
4539 }
4540 }
4541 }
4542
4543 break;
4544
4545 case 1: //horizontal
4546 if(dest[checktile].data!=NULL)
4547 {
4548 for(int32_t y=0; ((duplicate==true)&&(y<16)); y++)
4549 {
4550 for(int32_t x=0; ((duplicate==true)&&(x<16)); x+=3-newformat)
4551 {
4552 // if ((dest[(checktile*128)+(y*8)+((14-x)/2)])!=(((testtile[(y*8)+(x/2)]&15)<<4)+((testtile[(y*8)+(x/2)]>>4)&15)))
4553 if((dest[checktile].data[(y*8*newformat)+(14+(newformat-1)-x)/(3-newformat)])!=testtile[(y*16)+x])
4554 {
4555 duplicate=false;
4556 }
4557 }
4558 }
4559 }
4560
4561 break;
4562
4563 case 2: //vertical
4564 if(dest[checktile].data!=NULL)
4565 {
4566 for(int32_t y=0; ((duplicate==true)&&(y<16)); y++)
4567 {
4568 for(int32_t x=0; ((duplicate==true)&&(x<16)); x+=3-newformat)
4569 {
4570 // if ((dest[(checktile*128)+((15-y)*8)+(x/2)])!=(testtile[(y*8)+(x/2)]))
4571 if((dest[checktile].data[((15-y)*8*newformat)+(x/(3-newformat))])!=testtile[(y*16)+x])
4572 {
4573 duplicate=false;
4574 }
4575 }
4576 }
4577 }
4578
4579 break;
4580
4581 case 3: //both
4582 if(dest[checktile].data!=NULL)
4583 {
4584 for(int32_t y=0; ((duplicate==true)&&(y<16)); y++)
4585 {
4586 for(int32_t x=0; ((duplicate==true)&&(x<16)); x+=3-newformat)
4587 {
4588 // if ((dest[(checktile*128)+((15-y)*8)+((14-x)/2)])!=(((testtile[(y*8)+(x/2)]&15)<<4)+((testtile[(y*8)+(x/2)]>>4)&15)))
4589 if((dest[checktile].data[((15-y)*8*newformat)+((14+(newformat-1)-x)/(3-newformat))])!=testtile[(y*16)+x])
4590 {
4591 duplicate=false;
4592 }
4593 }
4594 }
4595 }
4596
4597 break;
4598 }
4599 }
4600
4601 if(duplicate==true)
4602 {
4603 ++duplicates_found[flipping];
4604 ++total_duplicates_found;
4605
4606 if(DuplicateAction[flipping]>1)
4607 {
4608 ++total_duplicates_discarded;
4609 temp_canadd=false;
4610 }
4611 }
4612 }
4613
4614 canadd=canadd&&temp_canadd;
4615 }
4616 }
4617 }
4618
4619 // dest[currtile].format=(cdepth==3?imported_format:cdepth);
4620 dest[currtile].format=newformat;
4621
4622 if(dest[currtile].data!=NULL)
4623 {
4624 free(dest[currtile].data);
4625 }
4626
4627 dest[currtile].data=(byte *)malloc(tilesize(dest[currtile].format));
4628
4629 if(dest[currtile].data==NULL)
4630 {
4631 Z_error_fatal("Unable to initialize tile #%d.\n", currtile);
4632 }
4633
4634 if(canadd==true)
4635 {
4636 /*
4637 for(int32_t y=0; y<16; y++)
4638 {
4639 for(int32_t x=0; x<8; x++)
4640 {
4641 dest[currtile].data[(y*8)+x]=testtile[(y*8)+x];
4642 }
4643 }
4644 */
4645 memcpy(dest[currtile].data, testtile, tilesize(dest[currtile].format));
4646 ++currtile;
4647 }
4648 }
4649 }
4650
4651 destroy_bitmap(status);
4652 delete[] testtile;
4653 return true;
4654 }
4655
4656 void grab(byte(*dest)[256],byte *def, int32_t width, int32_t height, int32_t oformat, byte *newformat)
4657 {
4658 byte defFormat=(bp==8) ? tf8Bit : tf4Bit;
4659 byte format=defFormat;
4660 int32_t stile = ((imagey*TILES_PER_ROW)+imagex)+(((sely/16)*TILES_PER_ROW)+(selx/16));
4661
4662 switch(imagetype)
4663 {
4664 case ftZGP:
4665 case ftQST:
4666 case ftZQT:
4667 case ftQSU:
4668 case ftTIL:
4669 case ftBIN:
4670 case ftBMP:
4671 for(int32_t ty=0; ty<height; ty++)
4672 {
4673 for(int32_t tx=0; tx<width; tx++)
4674 {
4675 format=defFormat;
4676 switch(imagetype)
4677 {
4678 case ftZGP:
4679 case ftQST:
4680 case ftZQT:
4681 case ftQSU:
4682 case ftTIL:
4683 format=grabtilebuf[stile+((ty*TILES_PER_ROW)+tx)].format;
4684 break;
4685 }
4686
4687 bool ever_did_unmasked = false;
4688
4689 for(int32_t y=0; y<16; y++)
4690 {
4691 for(int32_t x=0; x<16; x+=2)
4692 {
4693 bool masked = (y<8 && x<8 && grabmask&1) || (y<8 && x>7 && grabmask&2) || (y>7 && x<8 && grabmask&4) || (y>7 && x>7 && grabmask&8);
4694 if (masked)
4695 {
4696 dest[(ty*TILES_PER_ROW)+tx][(y*16)+(x)]=def[(y*16)+(x)];
4697 dest[(ty*TILES_PER_ROW)+tx][(y*16)+(x+1)]=def[(y*16)+(x+1)];
4698 }
4699 else
4700 {
4701 dest[(ty*TILES_PER_ROW)+tx][(y*16)+x]=getpixel(screen2,(tx*16)+x+selx,(ty*16)+y+sely);
4702 dest[(ty*TILES_PER_ROW)+tx][(y*16)+x+1]=getpixel(screen2,(tx*16)+x+1+selx,(ty*16)+y+sely);
4703 ever_did_unmasked = true;
4704 }
4705 if (format == tf4Bit)
4706 {
4707 dest[(ty*TILES_PER_ROW)+tx][(y*16)+x] &= 15;
4708 dest[(ty*TILES_PER_ROW)+tx][(y*16)+x+1] &= 15;
4709 }
4710 }
4711 }
4712
4713 if (ever_did_unmasked)
4714 newformat[(ty*TILES_PER_ROW)+tx] = format;
4715 }
4716 }
4717
4718 break;
4719
4720 default:
4721 for(int32_t i=0; i<200; i++)
4722 {
4723 for(int32_t j=0; j<256; j++)
4724 {
4725 dest[i][j]=0;
4726 }
4727
4728 newformat[i] = tf4Bit;
4729 }
4730
4731 break;
4732 }
4733 }
4734
4735 static void scale_imagebuf_bitmap()
4736 {
4737 imagebuf_bitmap_scale = std::clamp(imagebuf_bitmap_scale, -10, 10);
4738
4739 float scale = IMAGEBUF_SCALE;
4740 int nw = original_imagebuf_bitmap->w * scale;
4741 int nh = original_imagebuf_bitmap->h * scale;
4742 if (nw <= 0 || nh <= 0)
4743 return;
4744
4745 BITMAP* scaled_bmp = create_bitmap_ex(8, nw, nh);
4746 if (!scaled_bmp)
4747 return;
4748
4749 stretch_blit(original_imagebuf_bitmap, scaled_bmp, 0, 0, original_imagebuf_bitmap->w, original_imagebuf_bitmap->h, 0, 0, nw, nh);
4750 if (imagebuf != original_imagebuf_bitmap)
4751 destroy_bitmap((BITMAP*)imagebuf);
4752 imagebuf = scaled_bmp;
4753 }
4754
4755 //Grabber is not grabbing to tile pages beyond pg. 252 right now. -ZX 18th June, 2019
4756 void grab_tile(int32_t tile,int32_t &cs)
4757 {
4758 zq_allow_tile_draw_cache = true;
4759
4760 int window_w = 640+6+6, window_h = 480+25+6;
4761 int window_x=(zq_screen_w-window_w)/2;
4762 int window_y=(zq_screen_h-window_h)/2;
4763 popup_zqdialog_start(window_x,window_y,window_w,window_h,-1);
4764 int window_xofs = 0;
4765 int screen_xofs=6;
4766 int screen_yofs=25;
4767 int panel_yofs=0;
4768 int bwidth = 61*1.5;
4769 int bheight = 20*1.5;
4770 int button_x = 512 + 6;
4771 int grab_ok_button_y = 168*2 + 32 - 7;
4772 int leech_button_x = 117*2 + 7;
4773 int leech_button_y = 166*2 + 32 - 7;
4774 int grab_cancel_button_y = 192*2 + 32 - 7;
4775 int file_button_y = 216*2 + 32 - 7;
4776 int rec_button_x = 117*2 + 6;
4777 int rec_button_y = 192*2 + 32 - 7;
4778
4779 int screen_y1 = 24;
4780 int screen_y2 = screen_y1+320-1;
4781
4782 int crect_x = 184+190;
4783 int crect_y = 168*2 + 32;
4784 int crect_w = 8*2;
4785 int crect_h = 8*2;
4786
4787 int xrect_x = 640 + 12 - 21;
4788 int xrect_y = 5;
4789
4790 byte newtile[200][256];
4791 BITMAP *screen3=create_bitmap_ex(8, zq_screen_w, zq_screen_h);
4792 clear_bitmap(screen3);
4793 byte newformat[200];
4794
4795 memset(newtile, 0, 200*256);
4796 memset(newformat, 0, 200);
4797
4798 static EXT_LIST list[] =
4799 {
4800 { (char *)"All Files (*.*)", NULL },
4801 { (char *)"Bitmap Image (*.bmp)", (char *)"bmp" },
4802 { (char *)"GIF Image (*.gif)", (char *)"gif" },
4803 { (char *)"JPEG Image (*.jpg, *.jpeg)", (char *)"jpg,jpeg" },
4804 { (char *)"ZC Tile Export (*.til)", (char *)"til" },
4805 { (char *)"ZC Quest Template (*.zqt)", (char *)"zqt" },
4806 { (char *)"ZC Quest (*.qst)", (char *)"qst" },
4807 { (char *)"ZC Graphics Pack (*.zgp)", (char *)"zgp" },
4808 { (char *)"ZC Unencoded Quest (*.qsu)", (char *)"qsu" },
4809 { (char *)"NES ROM Image (*.nes)", (char *)"nes" },
4810 { (char *)"SNES ROM Image (*.smc)", (char *)"smc" },
4811 { (char *)"Gameboy ROM Image (*.gb)", (char *)"gb" },
4812 { (char *)"Gameboy Advance ROM Image (*.gba)", (char *)"gba" },
4813 { NULL, NULL }
4814 };
4815
4816
4817 memset(cset_reduce_table, 0, 256);
4818 memset(col_diff,0,3*128);
4819 bool bdown=false;
4820 int done=0;
4821 int pal=0;
4822 int black=vc(0),white=vc(15);
4823 int selwidth=1, selheight=1;
4824 int selx2=0, sely2=0;
4825 bool xreversed=false, yreversed=false;
4826 bool doleech=false, dofile=false, dopal=false;
4827
4828 int jwin_pal2[jcMAX];
4829 memcpy(jwin_pal2, jwin_pal, sizeof(int)*jcMAX);
4830
4831 if(imagebuf==NULL)
4832 load_imagebuf();
4833
4834 calc_cset_reduce_table(imagepal, cs);
4835 calc_cset_reduce_table_8bit(imagepal);
4836 draw_grab_window();
4837 draw_grab_scr(tile, cs, newtile[0], black, newformat, screen3);
4838 grab(newtile,newtilebuf[tile].data, selwidth, selheight, newtilebuf[tile].format, newformat);
4839
4840 auto do_anim = [&](bool redraw)
4841 {
4842 if (!(framecnt%8))
4843 redraw = true;
4844 if(redraw)
4845 {
4846 draw_grab_scr(tile, cs, newtile[0], black, newformat, screen3);
4847
4848 if(framecnt&8)
4849 rect(screen3, selx*2, sely*2,
4850 selx*2+((selwidth-1)*32)+(32-1), sely*2+((selheight-1)*32)+(32-1), white);
4851
4852 blit(screen3,screen,0,0,0+screen_xofs,0+screen_yofs,window_w-2*screen_xofs,window_h-2*screen_yofs);
4853 }
4854 anim_hw_screen();
4855 };
4856 while(gui_mouse_b()) ; // wait
4857
4858 do_anim(true);
4859 do
4860 {
4861 HANDLE_CLOSE_ZQDLG();
4862 if(exiting_program) break;
4863 //rest(4);
4864 bool redraw = false;
4865
4866 if(keypressed())
4867 {
4868 switch(readkey()>>8)
4869 {
4870 case KEY_F:
4871 dofile=true;
4872 break;
4873
4874 case KEY_L:
4875 doleech=true;
4876 break;
4877
4878 case KEY_P:
4879 if(imagetype==ftBMP)
4880 {
4881 dopal=true;
4882 recolor=rcNone;
4883 calc_cset_reduce_table(imagepal, cs);
4884 }
4885
4886 break;
4887
4888 case KEY_ESC:
4889 done=1;
4890 break;
4891
4892 case KEY_ENTER_PAD:
4893 case KEY_ENTER:
4894 done=2;
4895 break;
4896
4897 case KEY_DOWN:
4898 if(CHECK_CTRL_CMD) sely=zc_min(sely+1,144);
4899 else ++imagey;
4900
4901 break;
4902
4903 case KEY_UP:
4904 if(CHECK_CTRL_CMD) sely=zc_max(sely-1,0);
4905 else --imagey;
4906
4907 break;
4908
4909 case KEY_RIGHT:
4910 if(CHECK_CTRL_CMD) selx=zc_min(selx+1,304);
4911 else ++imagex;
4912
4913 break;
4914
4915 case KEY_LEFT:
4916 if(CHECK_CTRL_CMD) selx=zc_max(selx-1,0);
4917 else --imagex;
4918
4919 break;
4920
4921 case KEY_PGDN:
4922 imagey+=10;
4923 break;
4924
4925 case KEY_PGUP:
4926 imagey-=10;
4927 break;
4928
4929 case KEY_HOME:
4930 imagex=imagey=0;
4931 break;
4932
4933 case KEY_EQUALS:
4934 case KEY_PLUS_PAD:
4935 cs = (cs<13) ? cs+1:0;
4936 if(recolor==rc4Bit)
4937 calc_cset_reduce_table(imagepal, cs);
4938 break;
4939
4940 case KEY_MINUS:
4941 case KEY_MINUS_PAD:
4942 cs = (cs>0) ? cs-1:13;
4943 if(recolor==rc4Bit)
4944 calc_cset_reduce_table(imagepal, cs);
4945 break;
4946
4947 case KEY_S:
4948 if(grabmode==1) grabmode=8;
4949 else if(grabmode==8) grabmode=16;
4950 else grabmode=1;
4951
4952 break;
4953
4954 case KEY_COMMA:
4955 if (imagetype == ftBMP)
4956 {
4957 imagebuf_bitmap_scale--;
4958 if (imagebuf_bitmap_scale == 0)
4959 imagebuf_bitmap_scale = -2;
4960 scale_imagebuf_bitmap();
4961 }
4962 break;
4963 case KEY_STOP:
4964 if (imagetype == ftBMP)
4965 {
4966 imagebuf_bitmap_scale++;
4967 if (imagebuf_bitmap_scale == -1)
4968 imagebuf_bitmap_scale = 1;
4969 scale_imagebuf_bitmap();
4970 }
4971 break;
4972
4973 case KEY_1:
4974 if(recolor==rc8Bit)
4975 recolor=rcNone;
4976 //imagex=(imagex*bp)>>3;
4977 bp=1;
4978 //imagex<<=3;
4979 nesmode=false;
4980 break;
4981
4982 case KEY_2:
4983 if(recolor==rc8Bit)
4984 recolor=rcNone;
4985 //imagex=(imagex*bp)>>3;
4986 bp=2;
4987 //imagex<<=2;
4988 nesmode=false;
4989 break;
4990
4991 case KEY_N:
4992 if(recolor==rc8Bit)
4993 recolor=rcNone;
4994 //imagex=(imagex*bp)>>3;
4995 bp=2;
4996 //imagex<<=2;
4997 nesmode=true;
4998 break;
4999
5000 case KEY_4:
5001 if(recolor==rc8Bit)
5002 recolor=rcNone;
5003 //imagex=(imagex*bp)>>3;
5004 bp=4;
5005 //imagex<<=1;
5006 nesmode=false;
5007 break;
5008
5009 case KEY_8:
5010 //imagex=(imagex*bp)>>3;
5011 bp=8;
5012 break;
5013
5014 case KEY_B:
5015 if(bp==2&&!nesmode)
5016 {
5017 nesmode=true;
5018 }
5019 else
5020 {
5021 nesmode=false;
5022 bp<<=1;
5023
5024 if(bp==16)
5025 {
5026 bp=1;
5027 //imagex<<=3;
5028 }
5029 else
5030 {
5031 //imagex>>=1;
5032 }
5033 }
5034
5035 break;
5036
5037 case KEY_M:
5038 romtilemode=(romtilemode+1)%4;
5039 break;
5040
5041 case KEY_Z:
5042 if(romofs>0) --romofs;
5043
5044 break;
5045
5046 case KEY_X:
5047 ++romofs;
5048 break;
5049
5050 case KEY_R:
5051 if(pal)
5052 {
5053 dopal=true;
5054 }
5055
5056 if(recolor!=rcNone)
5057 recolor=rcNone;
5058 else if(key[KEY_LSHIFT] || key[KEY_RSHIFT])
5059 {
5060 bp=8;
5061 recolor=rc8Bit;
5062 calc_cset_reduce_table_8bit(imagepal);
5063 }
5064 else
5065 {
5066 if(bp==8)
5067 bp=4;
5068 recolor=rc4Bit;
5069 calc_cset_reduce_table(imagepal, cs);
5070 }
5071 break;
5072 }
5073
5074 clear_keybuf();
5075
5076 if(imagex<0) imagex=0;
5077
5078 if(imagey<0) imagey=0;
5079
5080 grab(newtile,newtilebuf[tile].data, selwidth, selheight, newtilebuf[tile].format, newformat);
5081
5082 do_anim(true);
5083 continue;
5084 }
5085
5086 //boogie!
5087 if(gui_mouse_b()==1 && !bdown)
5088 {
5089 int x=gui_mouse_x();
5090 int y=gui_mouse_y();
5091 if(isinRect(x,y,xrect_x, xrect_y, xrect_x + 15, xrect_y + 13))
5092 if(do_x_button(screen, xrect_x, xrect_y))
5093 done=1;
5094
5095 if(!bdown)
5096 {
5097 bool regrab=false;
5098 bdown=true;
5099 FONT* oldfont = font;
5100 font = get_zc_font(font_lfont_l);
5101
5102 if(y>=screen_y1 && y<=screen_y2)
5103 {
5104 do
5105 {
5106 HANDLE_CLOSE_ZQDLG();
5107 if(exiting_program) break;
5108 int x = (gui_mouse_x()-screen_xofs) / 2;
5109 int y = (gui_mouse_y()-screen_yofs) / 2;
5110
5111 int ox=selx,oy=sely,ow=selwidth,oh=selheight;
5112
5113 if(!(key[KEY_LSHIFT] || key[KEY_RSHIFT]))
5114 {
5115 selx=vbound((x/grabmode)*grabmode,0,304);
5116 sely=vbound((y/grabmode)*grabmode,0,144);
5117 selx2=selx;
5118 sely2=sely;
5119 selwidth=1;
5120 selheight=1;
5121 xreversed=false;
5122 yreversed=false;
5123 }
5124 else
5125 {
5126 if(xreversed)
5127 {
5128 zc_swap(selx, selx2);
5129 xreversed=false;
5130 }
5131
5132 if(yreversed)
5133 {
5134 zc_swap(sely, sely2);
5135 yreversed=false;
5136 }
5137
5138 selx2=vbound((x/grabmode)*grabmode,0,304);
5139 sely2=vbound((y/grabmode)*grabmode,0,144);
5140 selwidth=1+(abs(selx2-selx))/16;
5141 selheight=1+(abs(sely2-sely))/16;
5142
5143 if(selx2<selx)
5144 {
5145 zc_swap(selx, selx2);
5146 xreversed=true;
5147 }
5148
5149 if(sely2<sely)
5150 {
5151 zc_swap(sely, sely2);
5152 yreversed=true;
5153 }
5154 }
5155
5156 bool changed = (ox!=selx || oy!=sely || ow!=selwidth || oh!=selheight);
5157
5158 if(changed || !(framecnt%8))
5159 grab(newtile,newtilebuf[tile].data, selwidth, selheight, newtilebuf[tile].format, newformat);
5160 do_anim(changed);
5161 }
5162 while(gui_mouse_b());
5163 font = oldfont;
5164 continue;
5165 }
5166 else if(isinRect(x,y,button_x,grab_ok_button_y,button_x+bwidth,grab_ok_button_y+bheight))
5167 {
5168 if(do_text_button(button_x,grab_ok_button_y,bwidth,bheight,"OK"))
5169 done=2;
5170 }
5171 else if(isinRect(x,y,leech_button_x,leech_button_y,leech_button_x+bwidth,leech_button_y+bheight))
5172 {
5173 if(do_text_button(leech_button_x,leech_button_y,bwidth,bheight,"Leech"))
5174 {
5175 doleech=true;
5176 }
5177 }
5178 else if(isinRect(x,y,button_x,grab_cancel_button_y,button_x+bwidth,grab_cancel_button_y+bheight))
5179 {
5180 if(do_text_button(button_x,grab_cancel_button_y,bwidth,bheight,"Cancel"))
5181 done=1;
5182 }
5183 else if(isinRect(x,y,button_x,file_button_y,button_x+bwidth,file_button_y+bheight))
5184 {
5185 if(do_text_button(button_x,file_button_y,bwidth,bheight,"File"))
5186 {
5187 dofile=true;
5188 }
5189 }
5190 else if(imagetype == ftBMP && isinRect(x,y,rec_button_x, rec_button_y, rec_button_x+bwidth, rec_button_y+bheight))
5191 {
5192 if(do_text_button(rec_button_x,rec_button_y,bwidth,bheight,"Recolor"))
5193 {
5194 if(pal)
5195 {
5196 dopal = true;
5197 }
5198
5199 if(recolor!=rcNone)
5200 recolor=rcNone;
5201 else if(key[KEY_LSHIFT] || key[KEY_RSHIFT])
5202 {
5203 bp=8;
5204 recolor=rc8Bit;
5205 calc_cset_reduce_table_8bit(imagepal);
5206 }
5207 else
5208 {
5209 if(bp==8)
5210 bp=4;
5211 recolor=rc4Bit;
5212 calc_cset_reduce_table(imagepal, cs);
5213 }
5214 }
5215 }
5216 else if(isinRect(x,y+panel_yofs,crect_x,crect_y,crect_x+(16),crect_y+crect_h-1))
5217 {
5218 regrab=true;
5219 grabmask^=1;
5220 }
5221 else if(isinRect(x,y+panel_yofs,crect_x+crect_w,crect_y,crect_x+(32)-1,crect_y+crect_h-1))
5222 {
5223 regrab=true;
5224 grabmask^=2;
5225 }
5226 else if(isinRect(x,y+panel_yofs,crect_x,crect_y+crect_h,crect_x+(16)-1,crect_y+crect_h+crect_h-1))
5227 {
5228 regrab=true;
5229 grabmask^=4;
5230 }
5231 else if(isinRect(x,y+panel_yofs,crect_x+crect_w,crect_y+crect_h,crect_x+(32)-1,crect_y+crect_h+crect_h-1))
5232 {
5233 regrab=true;
5234 grabmask^=8;
5235 }
5236
5237 font = oldfont;
5238
5239 if(regrab)
5240 {
5241 grab(newtile,newtilebuf[tile].data, selwidth, selheight, newtilebuf[tile].format, newformat);
5242 do_anim(true);
5243 continue;
5244 }
5245 }
5246 }
5247
5248 if(gui_mouse_b()==0)
5249 bdown=false;
5250
5251 if(dofile)
5252 {
5253 if (prompt_for_existing_file_compat("Load File", "", list, imagepath, true))
5254 {
5255 zc_set_palette(RAMpal);
5256 pal=0;
5257 white=vc(15);
5258 black=vc(0);
5259 strcpy(imagepath,temppath);
5260 load_imagebuf();
5261 imagex=imagey=0;
5262 calc_cset_reduce_table(imagepal, cs);
5263 grab(newtile,newtilebuf[tile].data, selwidth, selheight, newtilebuf[tile].format, newformat);
5264 }
5265
5266 while(key[KEY_ESC])
5267 {
5268 poll_keyboard();
5269 /* do nothing */
5270 rest(1);
5271 }
5272
5273 clear_keybuf();
5274 dofile = false;
5275 do_anim(true);
5276 continue;
5277 }
5278
5279 if(doleech)
5280 {
5281 if(leech_tiles(newtilebuf,tile,cs))
5282 {
5283 done=1;
5284 }
5285 else
5286 {
5287 while(key[KEY_ESC])
5288 {
5289 poll_keyboard();
5290 /* do nothing */
5291 rest(1);
5292 }
5293
5294 clear_keybuf();
5295 redraw = true;
5296 }
5297
5298 doleech = false;
5299 }
5300
5301 if(dopal)
5302 {
5303 pal^=1;
5304
5305 if(pal)
5306 {
5307 get_bw(imagepal,black,white);
5308
5309 jwin_pal[jcBOX] =imagepal_table.data[0][jwin_pal[jcBOX]];
5310 jwin_pal[jcLIGHT] =imagepal_table.data[0][jwin_pal[jcLIGHT]];
5311 jwin_pal[jcMEDLT] =imagepal_table.data[0][jwin_pal[jcMEDLT]];
5312 jwin_pal[jcMEDDARK]=imagepal_table.data[0][jwin_pal[jcMEDDARK]];
5313 jwin_pal[jcDARK] =imagepal_table.data[0][jwin_pal[jcDARK]];
5314 jwin_pal[jcBOXFG] =imagepal_table.data[0][jwin_pal[jcBOXFG]];
5315 jwin_pal[jcTITLEL] =imagepal_table.data[0][jwin_pal[jcTITLEL]];
5316 jwin_pal[jcTITLER] =imagepal_table.data[0][jwin_pal[jcTITLER]];
5317 jwin_pal[jcTITLEFG]=imagepal_table.data[0][jwin_pal[jcTITLEFG]];
5318 jwin_pal[jcTEXTBG] =imagepal_table.data[0][jwin_pal[jcTEXTBG]];
5319 jwin_pal[jcTEXTFG] =imagepal_table.data[0][jwin_pal[jcTEXTFG]];
5320 jwin_pal[jcSELBG] =imagepal_table.data[0][jwin_pal[jcSELBG]];
5321 jwin_pal[jcSELFG] =imagepal_table.data[0][jwin_pal[jcSELFG]];
5322 gui_bg_color=jwin_pal[jcBOX];
5323 gui_fg_color=jwin_pal[jcBOXFG];
5324 jwin_set_colors(jwin_pal);
5325 }
5326 else
5327 {
5328 white=vc(15);
5329 black=vc(0);
5330
5331 memcpy(jwin_pal, jwin_pal2, sizeof(int)*jcMAX);
5332 gui_bg_color=jwin_pal[jcBOX];
5333 gui_fg_color=jwin_pal[jcBOXFG];
5334 jwin_set_colors(jwin_pal);
5335 }
5336
5337 zc_set_palette_range(pal?imagepal:RAMpal,0,255,false);
5338
5339 dopal = false;
5340 redraw = true;
5341 }
5342
5343 do_anim(redraw);
5344 }
5345 while(!done);
5346
5347 memcpy(jwin_pal, jwin_pal2, sizeof(int)*jcMAX);
5348 gui_bg_color=jwin_pal[jcBOX];
5349 gui_fg_color=jwin_pal[jcBOXFG];
5350 jwin_set_colors(jwin_pal);
5351
5352
5353 if(done==2)
5354 {
5355 go_tiles();
5356 mark_save_dirty();
5357
5358 for(int y=0; y<selheight; y++)
5359 {
5360 for(int x=0; x<selwidth; x++)
5361 {
5362 int temptile=tile+((TILES_PER_ROW*y)+x);
5363 int format=(bp==8) ? tf8Bit : tf4Bit;
5364
5365 if(newtilebuf[temptile].data!=NULL)
5366 free(newtilebuf[temptile].data);
5367
5368 newtilebuf[temptile].format=format;
5369 newtilebuf[temptile].data=(byte *)malloc(tilesize(format));
5370
5371 if(newtilebuf[temptile].data==NULL)
5372 {
5373 Z_error_fatal("Unable to initialize tile #%d.\n", temptile);
5374 break;
5375 }
5376
5377 for(int i=0; i<256; i++)
5378 {
5379 // newtilebuf[temptile].data[i] = cset_reduce_table[newtile[(TILES_PER_ROW*y)+x][i]];
5380 newtilebuf[temptile].data[i] = newtile[(TILES_PER_ROW*y)+x][i];
5381 }
5382
5383 // unpackbuf[i]=(cset_reduce_table[unpackbuf[i]]);
5384 }
5385 }
5386 }
5387
5388 destroy_bitmap(screen3);
5389
5390 if(pal)
5391 zc_set_palette(RAMpal);
5392
5393 recolor=rcNone;
5394 calc_cset_reduce_table(imagepal, cs);
5395 register_blank_tiles();
5396 popup_zqdialog_end();
5397
5398 zq_allow_tile_draw_cache = false;
5399 }
5400
5401 int32_t show_only_unused_tiles=4; //1 bit: hide used, 2 bit: hide unused, 4 bit: hide blank
5402 bool tile_is_used(int32_t tile)
5403 {
5404 return used_tile_table[tile];
5405 }
5406 void draw_tiles(int32_t first,int32_t cs)
5407 {
5408 draw_tiles(screen2, first, cs, true);
5409 }
5410 void draw_tiles(BITMAP* dest,int32_t first,int32_t cs, bool large, bool true_empty)
5411 {
5412 clear_bitmap(dest);
5413 BITMAP *buf = create_bitmap_ex(8,16,16);
5414
5415 int32_t w = 16;
5416 int32_t h = 16;
5417
5418 if(large)
5419 {
5420 w *=2;
5421 h *=2;
5422 }
5423
5424 for(int32_t i=0; i<TILES_PER_PAGE; i++) // 13 rows, leaving 32 pixels from y=208 to y=239
5425 {
5426 int32_t x = (i%TILES_PER_ROW)<<4;
5427 int32_t y = (i/TILES_PER_ROW)<<4;
5428 int32_t l = 16;
5429
5430 if(large)
5431 {
5432 x*=2;
5433 y*=2;
5434 l*=2;
5435 }
5436
5437 l-=2;
5438
5439 if((HIDE_USED && tile_is_used(first+i) && !blank_tile_table[first+i]) // 1 bit: hide used
5440 || (HIDE_UNUSED && !tile_is_used(first+i) && !blank_tile_table[first+i]) // 2 bit: hide unused
5441 || (HIDE_BLANK && blank_tile_table[first+i])) // 4 bit: hide blank
5442 {
5443 if(!true_empty) //Use pure color 0; no effects
5444 {
5445 if (InvalidBG == 2)
5446 {
5447 draw_checkerboard(dest, x, y, w);
5448 }
5449 else if(InvalidBG == 1)
5450 {
5451 draw_static(dest, x, y, l+1, l+1);
5452 }
5453 else
5454 {
5455 for(int32_t dy=0; dy<=l+1; dy++)
5456 {
5457 for(int32_t dx=0; dx<=l+1; dx++)
5458 {
5459 dest->line[dy+(y)][dx+(x)]=vc(0);
5460 }
5461 }
5462 rect(dest, (x)+1,(y)+1, (x)+l, (y)+l, vc(15));
5463 line(dest, (x)+1,(y)+1, (x)+l, (y)+l, vc(15));
5464 line(dest, (x)+1,(y)+l, (x)+l, (y)+1, vc(15));
5465 }
5466 }
5467 }
5468 else
5469 {
5470 puttile16(buf,first+i,0,0,cs,0);
5471 stretch_blit(buf,dest,0,0,16,16,x,y,w,h);
5472 }
5473
5474 if((framecnt%32)<=16 && large && !HIDE_8BIT_MARKER && newtilebuf[first+i].format==tf8Bit)
5475 {
5476 textprintf_ex(dest,get_zc_font(font_z3smallfont),(x)+l-3,(y)+l-3,vc(int32_t((framecnt%32)/6)+10),-1,"8");
5477 }
5478 }
5479
5480 destroy_bitmap(buf);
5481 }
5482
5483 void tile_info_0(int32_t tile,int32_t tile2,int32_t cs,int32_t copy,int32_t copycnt,int32_t page,bool rect_sel)
5484 {
5485 int32_t yofs=3;
5486 BITMAP *buf = create_bitmap_ex(8,16,16);
5487 int32_t mul = 2;
5488 FONT *tfont = get_zc_font(font_pfont);
5489
5490 rectfill(screen2,0,210*2,(320*2)-1,(240*2),jwin_pal[jcBOX]);
5491 hline(screen2, 0, (210*2)-2, (320*2)-1, jwin_pal[jcMEDLT]);
5492 hline(screen2, 0, (210*2)-1, (320*2)-1, jwin_pal[jcLIGHT]);
5493 tfont = get_zc_font(font_lfont_l);
5494
5495 // Copied tile and numbers
5496 jwin_draw_frame(screen2,(34*mul)-2,((216*mul)+yofs)-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
5497 int32_t coldiff=TILECOL(copy)-TILECOL(copy+copycnt-1);
5498 if(copy>=0)
5499 {
5500 puttile16(buf,rect_sel&&coldiff>0?copy-coldiff:copy,0,0,cs,0);
5501 stretch_blit(buf,screen2,0,0,16,16,34*mul,216*mul+yofs,16*mul,16*mul);
5502
5503 if(copycnt>1)
5504 {
5505 textprintf_right_ex(screen2,tfont,28*mul,(216*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d-",copy);
5506 textprintf_right_ex(screen2,tfont,24*mul,(224*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",copy+copycnt-1);
5507 }
5508 else
5509 {
5510 textprintf_right_ex(screen2,tfont,24*mul,(220*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",copy);
5511 }
5512 }
5513 else // No tiles copied
5514 {
5515 if (InvalidBG == 2)
5516 {
5517 draw_checkerboard(screen2, 34 * mul, 216 * mul + yofs, 16 * mul);
5518 }
5519 else if(InvalidBG == 1)
5520 {
5521 draw_static(screen2, 36*mul, 216*mul+yofs, 16*mul, 16*mul);
5522 }
5523 else
5524 {
5525 rectfill(screen2, 34*mul, (216*mul)+yofs, (34+15)*mul, ((216+15)*mul)+yofs, vc(0));
5526 rect(screen2, 34*mul, (216*mul)+yofs, (34+15)*mul, ((216+15)*mul)+yofs, vc(15));
5527 line(screen2, 34*mul, (216*mul)+yofs, (34+15)*mul, ((216+15)*mul)+yofs, vc(15));
5528 line(screen2, 34*mul, ((216+15)*mul)+yofs, (34+15)*mul, (216*mul)+yofs, vc(15));
5529 }
5530 }
5531
5532
5533 // Current tile
5534 jwin_draw_frame(screen2,(104*mul)-2,(216*mul+yofs)-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
5535 puttile16(buf,tile,0,0,cs,0);
5536 stretch_blit(buf,screen2,0,0,16,16,104*mul,216*mul+yofs,16*mul,16*mul);
5537
5538 // Current selection mode
5539 jwin_draw_frame(screen2,(127*mul)-2,(216*mul+yofs)-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
5540 stretch_blit(select_bmp[rect_sel?1:0],screen2,0,0,16,16,127*mul,216*mul+yofs,16*mul,16*mul);
5541
5542 if(tile>tile2)
5543 {
5544 zc_swap(tile,tile2);
5545 }
5546
5547 char tbuf[8];
5548 tbuf[0]=0;
5549
5550 if(tile2!=tile)
5551 {
5552 sprintf(tbuf,"-%d",tile2);
5553 }
5554
5555 // Current tile and CSet text
5556 textprintf_ex(screen2,tfont,55*mul,216*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"cs: %d",cs);
5557 textprintf_right_ex(screen2,tfont,99*mul,216*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"tile:");
5558 textprintf_right_ex(screen2,tfont,99*mul,224*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d%s",tile,tbuf);
5559
5560 FONT *tf = font;
5561 font = tfont;
5562
5563 draw_text_button(screen2,150*mul,213*mul+yofs,28*mul,21*mul,"&Grab",jwin_pal[jcBOXFG],jwin_pal[jcBOX],0,true);
5564 draw_text_button(screen2,(150+28)*mul,213*mul+yofs,28*mul,21*mul,"&Edit",jwin_pal[jcBOXFG],jwin_pal[jcBOX],0,true);
5565 draw_text_button(screen2,(150+28*2)*mul,213*mul+yofs,28*mul,21*mul,"Export",jwin_pal[jcBOXFG],jwin_pal[jcBOX],0,true);
5566 draw_text_button(screen2,(150+28*3)*mul,213*mul+yofs,28*mul,21*mul,"Recolor",jwin_pal[jcBOXFG],jwin_pal[jcBOX],0,true);
5567 draw_text_button(screen2,(150+28*4)*mul,213*mul+yofs,28*mul,21*mul,"Done",jwin_pal[jcBOXFG],jwin_pal[jcBOX],0,true);
5568
5569 jwin_draw_icon(screen2,(305*mul+4),220*mul-6+yofs,jwin_pal[jcBOXFG],BTNICON_ARROW_UP,6,true);
5570 textprintf_ex(screen2,tfont,293*mul,220*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"p:");
5571 textprintf_centre_ex(screen2,tfont,(305*mul+4),220*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",page);
5572 jwin_draw_icon(screen2,(305*mul+4),228*mul+3+yofs,jwin_pal[jcBOXFG],BTNICON_ARROW_DOWN,6,true);
5573
5574 font = tf;
5575
5576 int32_t w = 640;
5577 int32_t h = 480;
5578 int32_t window_xofs=(zq_screen_w-w-12)>>1;
5579 int32_t window_yofs=(zq_screen_h-h-25-6)>>1;
5580 int32_t screen_xofs=window_xofs+6;
5581 int32_t screen_yofs=window_yofs+25;
5582
5583 blit(screen2,screen,0,0,screen_xofs,screen_yofs,w,h);
5584 }
5585
5586 void tile_info_1(int32_t oldtile,int32_t oldflip,int32_t oldcs,int32_t tile,int32_t flip,int32_t cs,int32_t copy,int32_t page, bool always_use_flip)
5587 {
5588 int32_t yofs=3;
5589 BITMAP *buf = create_bitmap_ex(8,16,16);
5590 int32_t mul = 2;
5591 FONT *tfont = get_zc_font(font_pfont);
5592
5593 rectfill(screen2,0,210*2,(320*2)-1,(240*2),jwin_pal[jcBOX]);
5594 hline(screen2, 0, (210*2)-2, (320*2)-1, jwin_pal[jcMEDLT]);
5595 hline(screen2, 0, (210*2)-1, (320*2)-1, jwin_pal[jcLIGHT]);
5596 tfont = get_zc_font(font_lfont_l);
5597
5598 jwin_draw_frame(screen2,(124*mul)-2,((216*mul)+yofs)-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
5599
5600 if(copy>=0)
5601 {
5602 puttile16(buf,copy,0,0,cs,flip);
5603 stretch_blit(buf,screen2,0,0,16,16,124*mul,216*mul+yofs,16*mul,16*mul);
5604 }
5605 else
5606 {
5607 if (InvalidBG == 2)
5608 {
5609 draw_checkerboard(screen2, 124 * mul, 216 * mul + yofs, 16 * mul);
5610 }
5611 else if(InvalidBG == 1)
5612 {
5613 draw_static(screen2, 124*mul, 216*mul+yofs, 16*mul, 16*mul);
5614 }
5615 else
5616 {
5617 rectfill(screen2, 124*mul, (216*mul)+yofs, (124+15)*mul, ((216+15)*mul)+yofs, vc(0));
5618 rect(screen2, 124*mul, (216*mul)+yofs, (124+15)*mul, ((216+15)*mul)+yofs, vc(15));
5619 line(screen2, 124*mul, (216*mul)+yofs, (124+15)*mul, ((216+15)*mul)+yofs, vc(15));
5620 line(screen2, 124*mul, ((216+15)*mul)+yofs, (124+15)*mul, (216*mul)+yofs, vc(15));
5621 }
5622 }
5623
5624 jwin_draw_frame(screen2,(8*mul)-2,(216*mul+yofs)-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
5625 puttile16(buf,oldtile,0,0, oldcs, oldflip);
5626 stretch_blit(buf,screen2,0,0,16,16,8*mul,216*mul+yofs,16*mul,16*mul);
5627
5628 textprintf_right_ex(screen2,tfont,56*mul,212*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"Old Tile:");
5629 textprintf_ex(screen2,tfont,60*mul,212*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",oldtile);
5630
5631 textprintf_right_ex(screen2,tfont,56*mul,220*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"CSet:");
5632 textprintf_ex(screen2,tfont,60*mul,220*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",oldcs);
5633
5634 if(oldflip > 0 || always_use_flip) // Suppress Flip for this usage
5635 {
5636 textprintf_right_ex(screen2,tfont,56*mul,228*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"Flip:");
5637 textprintf_ex(screen2,tfont,60*mul,228*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",oldflip);
5638 }
5639
5640 jwin_draw_frame(screen2,(148*mul)-2,(216*mul+yofs)-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
5641 puttile16(buf,tile,0,0, cs,
5642 (oldflip>0 || always_use_flip)?flip:0); // Suppress Flip for this usage
5643 stretch_blit(buf,screen2,0,0,16,16,148*mul,216*mul+yofs,16*mul,16*mul);
5644
5645 textprintf_right_ex(screen2,tfont,201*mul,212*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"New Tile:");
5646 textprintf_ex(screen2,tfont,205*mul,212*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",tile);
5647 textprintf_right_ex(screen2,tfont,201*mul,220*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"CSet:");
5648 textprintf_ex(screen2,tfont,205*mul,220*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",cs);
5649
5650 if(oldflip > 0 || always_use_flip) // Suppress Flip for this usage
5651 {
5652 textprintf_right_ex(screen2,tfont,201*mul,228*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"Flip:");
5653 textprintf_ex(screen2,tfont,205*mul,228*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",flip);
5654 }
5655
5656 jwin_draw_icon(screen2,(305*mul+4),220*mul-6+yofs,jwin_pal[jcBOXFG],BTNICON_ARROW_UP,6,true);
5657 textprintf_ex(screen2,tfont,293*mul,220*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"p:");
5658 textprintf_centre_ex(screen2,tfont,309*mul,220*mul+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",page);
5659 jwin_draw_icon(screen2,(305*mul+4),228*mul+3+yofs,jwin_pal[jcBOXFG],BTNICON_ARROW_DOWN,6,true);
5660
5661
5662 int32_t w = 640;
5663 int32_t h = 480;
5664 int32_t window_xofs=(zq_screen_w-w-12)>>1;
5665 int32_t window_yofs=(zq_screen_h-h-25-6)>>1;
5666 int32_t screen_xofs=window_xofs+6;
5667 int32_t screen_yofs=window_yofs+25;
5668
5669 blit(screen2,screen,0,0,screen_xofs,screen_yofs,w,h);
5670 }
5671 /*
5672 void reset_tile(tiledata *buf, int32_t t, int32_t format=1)
5673 {
5674 buf[t].format=format;
5675 if (buf[t].data!=NULL)
5676 {
5677 free(buf[t].data);
5678 }
5679 buf[t].data=(byte *)malloc(tilesize(buf[t].format));
5680 if (buf[t].data==NULL)
5681 {
5682 Z_error_fatal("Unable to initialize tile #%d.\n", t);
5683 }
5684 for(int32_t i=0; i<tilesize(buf[t].format); i++)
5685 {
5686 buf[t].data[i]=0;
5687 }
5688 }
5689 */
5690
5691 int32_t hide_used()
5692 {
5693 show_only_unused_tiles ^= 1;
5694 return D_O_K;
5695 }
5696 int32_t hide_unused()
5697 {
5698 show_only_unused_tiles ^= 2;
5699 return D_O_K;
5700 }
5701 int32_t hide_blank()
5702 {
5703 show_only_unused_tiles ^= 4;
5704 return D_O_K;
5705 }
5706 int32_t hide_8bit_marker()
5707 {
5708 show_only_unused_tiles ^= 8;
5709 return D_O_K;
5710 }
5711
5712 enum
5713 {
5714 MENUID_SELTILE_VIEW_HIDE_USED,
5715 MENUID_SELTILE_VIEW_HIDE_UNUSED,
5716 MENUID_SELTILE_VIEW_HIDE_BLANK,
5717 MENUID_SELTILE_VIEW_HIDE_8BIT,
5718 };
5719
1/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12 static NewMenu select_tile_view_menu
5720 60 {
5721
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 { "Hide Used", hide_used, MENUID_SELTILE_VIEW_HIDE_USED },
5722
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 { "Hide Unused", hide_unused, MENUID_SELTILE_VIEW_HIDE_UNUSED },
5723
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 { "Hide Blank", hide_blank, MENUID_SELTILE_VIEW_HIDE_BLANK },
5724
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 { "Hide 8-bit marker", hide_8bit_marker, MENUID_SELTILE_VIEW_HIDE_8BIT },
5725 };
5726
5727 12 static std::function<void(int)> select_tile_color_depth_cb;
5728
5729 static void set_tile_color_depth_4()
5730 {
5731 select_tile_color_depth_cb(tf4Bit);
5732 }
5733 static void set_tile_color_depth_8()
5734 {
5735 select_tile_color_depth_cb(tf8Bit);
5736 }
5737 enum
5738 {
5739 MENUID_SELTILE_COLOR_DEPTH_4_BIT,
5740 MENUID_SELTILE_COLOR_DEPTH_8_BIT,
5741 };
5742
1/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12 static NewMenu select_tile_color_depth_menu
5743 36 {
5744
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 { "4-bit", set_tile_color_depth_4, MENUID_SELTILE_COLOR_DEPTH_4_BIT },
5745
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 { "8-bit", set_tile_color_depth_8, MENUID_SELTILE_COLOR_DEPTH_8_BIT },
5746 };
5747
5748 //returns the row the tile is in on its page
5749 int32_t tile_page_row(int32_t tile)
5750 {
5751 return TILEROW(tile)-(TILEPAGE(tile)*TILE_ROWS_PER_PAGE);
5752 }
5753
5754 enum {ti_none, ti_encompass, ti_broken};
5755
5756 //striped check and striped selection
5757 int32_t move_intersection_ss(newcombo &cmb, int32_t selection_first, int32_t selection_last, int32_t offset = 0)
5758 {
5759 int32_t cmb_first = cmb.o_tile;
5760 int32_t cmb_last = cmb.o_tile;
5761 do
5762 {
5763 cmb_last = cmb.tile;
5764 animate(cmb, true);
5765 }
5766 while(cmb.tile != cmb.o_tile);
5767 reset_combo_animation(cmb);
5768 cmb_first += offset;
5769 cmb_last += offset;
5770
5771 if(cmb_first > selection_last || cmb_last < selection_first)
5772 return ti_none;
5773 if(cmb_first >= selection_first && cmb_last <= selection_last)
5774 return ti_encompass;
5775
5776 do
5777 {
5778 if(cmb.tile+offset >= selection_first && cmb.tile+offset <= selection_last)
5779 {
5780 reset_combo_animation(cmb);
5781 return ti_broken; //contained, but non-encompassing.
5782 }
5783 animate(cmb, true);
5784 }
5785 while(cmb.tile != cmb.o_tile);
5786 reset_combo_animation(cmb);
5787 return ti_none;
5788 }
5789 int32_t move_intersection_ss(int32_t check_first, int32_t check_last, int32_t selection_first, int32_t selection_last)
5790 {
5791 // if selection is before or after check...
5792 if((check_first>selection_last)||(selection_first>check_last))
5793 {
5794 return ti_none;
5795 }
5796
5797 // if selection envelopes check
5798 if((selection_first<=check_first)&&(selection_last>=check_last))
5799 {
5800 return ti_encompass; //encompass
5801 }
5802
5803 //everything else is a break
5804 return ti_broken; //intersect
5805 }
5806
5807
5808
5809 //rectangular check and striped selection
5810 int32_t move_intersection_rs(int32_t check_left, int32_t check_top, int32_t check_width, int32_t check_height, int32_t selection_first, int32_t selection_last)
5811 {
5812 int32_t ret1=-1, ret2=-1;
5813
5814 for(int32_t i=0; i<check_height; ++i)
5815 {
5816 int32_t check_first=((check_top+i)*TILES_PER_ROW)+check_left;
5817 int32_t check_last=check_first+check_width-1;
5818 ret2=move_intersection_ss(check_first, check_last, selection_first, selection_last);
5819
5820 if(ret2==ti_broken)
5821 {
5822 return ti_broken;
5823 }
5824
5825 ret1=(ret2==ti_encompass?ti_encompass:ret1);
5826 }
5827
5828 if(ret1==ti_encompass)
5829 {
5830 if((TILEROW(selection_first)<=check_top) &&
5831 (TILEROW(selection_last)>=(check_top+check_height-1)))
5832 {
5833 return ti_encompass;
5834 }
5835 else
5836 {
5837 return ti_broken;
5838 }
5839 }
5840
5841 return ti_none;
5842 }
5843
5844
5845 //striped check and rectangular selection
5846 int32_t move_intersection_sr(newcombo &cmb, int32_t selection_left, int32_t selection_top, int32_t selection_width, int32_t selection_height, int32_t offset = 0)
5847 {
5848 if(selection_width < TILES_PER_ROW)
5849 {
5850 int32_t cmb_first = cmb.o_tile;
5851 int32_t cmb_last = cmb.o_tile;
5852 do
5853 {
5854 cmb_last = cmb.tile;
5855 animate(cmb, true);
5856 }
5857 while(cmb.tile != cmb.o_tile);
5858 reset_combo_animation(cmb);
5859 cmb_first += offset;
5860 cmb_last += offset;
5861
5862 if((TILEROW(cmb_first)>=selection_top) &&
5863 (TILEROW(cmb_last)<=selection_top+selection_height-1) &&
5864 (TILECOL(cmb_first)>=selection_left) &&
5865 (TILECOL(cmb_last)<=TILECOL(selection_left+selection_width-1)))
5866 {
5867 return ti_encompass;
5868 }
5869 else if((cmb_last<selection_top*TILES_PER_ROW+selection_left) ||
5870 (cmb_first>(selection_top+selection_height-1)*TILES_PER_ROW+selection_left+selection_width-1))
5871 {
5872 return ti_none;
5873 }
5874
5875 if(TILEROW(cmb_first) == TILEROW(cmb_last))
5876 {
5877 int32_t firstcol = TILECOL(cmb_first);
5878 int32_t lastcol = TILECOL(cmb_last);
5879
5880 if(lastcol < selection_left || firstcol >= selection_left+selection_width)
5881 return ti_none;
5882 else //handle skip x
5883 {
5884 do
5885 {
5886 if(TILECOL(cmb.tile) >= selection_left && TILECOL(cmb.tile) <= selection_left+selection_width)
5887 {
5888 reset_combo_animation(cmb);
5889 return ti_broken;
5890 }
5891 animate(cmb, true);
5892 }
5893 while(cmb.tile != cmb.o_tile);
5894 reset_combo_animation(cmb);
5895 return ti_none;
5896 }
5897 }
5898 else //multi-row combo...
5899 {
5900 int32_t row = TILEROW(cmb_first);
5901
5902 do
5903 {
5904 if(row < selection_top || row > selection_top+selection_height-1)
5905 {
5906 //This row isn't in the selection; skip to next row
5907 do
5908 {
5909 animate(cmb,true);
5910 if(cmb.tile == cmb.o_tile) return ti_none; //reached end
5911 }
5912 while(TILEROW(cmb.tile) == row);
5913 row = TILEROW(cmb.tile);
5914 continue;
5915 }
5916
5917 //This row IS in the selection; check each tile.
5918 do
5919 {
5920 if(TILECOL(cmb.tile) >= selection_left && TILECOL(cmb.tile) <= selection_left+selection_width-1)
5921 {
5922 reset_combo_animation(cmb);
5923 return ti_broken;
5924 }
5925 animate(cmb, true);
5926 if(cmb.tile == cmb.o_tile) return ti_none; //reached end
5927 }
5928 while(TILEROW(cmb.tile) == row);
5929 row = TILEROW(cmb.tile);
5930 }
5931 while(cmb.tile != cmb.o_tile);
5932
5933 return ti_none; //...Theoretically unreachable, but if it DOES get here, it's done.
5934 }
5935 }
5936
5937 return move_intersection_ss(cmb, selection_top*TILES_PER_ROW+selection_left, (selection_top+selection_height-1)*TILES_PER_ROW+selection_left+selection_width-1, offset);
5938 }
5939 int32_t move_intersection_sr(int32_t check_first, int32_t check_last, int32_t selection_left, int32_t selection_top, int32_t selection_width, int32_t selection_height)
5940 {
5941 if(selection_width < TILES_PER_ROW)
5942 {
5943 if((check_last-check_first+1<=selection_width) &&
5944 (TILEROW(check_first)>=selection_top) &&
5945 (TILEROW(check_last)<=selection_top+selection_height-1) &&
5946 (TILECOL(check_first)>=selection_left) &&
5947 (TILECOL(check_last)<=TILECOL(selection_left+selection_width-1)))
5948 {
5949 return ti_encompass;
5950 }
5951 else if((check_last<selection_top*TILES_PER_ROW+selection_left) ||
5952 (check_first>(selection_top+selection_height-1)*TILES_PER_ROW+selection_left+selection_width-1))
5953 {
5954 return ti_none;
5955 }
5956
5957 //else if (selection_top*TILES_PER_ROW+selection_left<check_first && (selection_top+1)*TILES_PER_ROW+selection_left>check_last)
5958
5959 //one last base case: the strip we're interested in only lies along one row
5960 if(check_first/TILES_PER_ROW == check_last/TILES_PER_ROW)
5961 {
5962 int32_t cfcol = check_first%TILES_PER_ROW;
5963 int32_t clcol = check_last%TILES_PER_ROW;
5964
5965 if(clcol < selection_left || cfcol >= selection_left+selection_width)
5966 return ti_none;
5967 else
5968 return ti_broken;
5969 }
5970 else
5971 {
5972 //recursively cut the strip into substrips which lie entirely on one row
5973 int32_t currow = check_first/TILES_PER_ROW;
5974 int32_t endrow = check_last/TILES_PER_ROW;
5975 int32_t accum = 0;
5976 accum |= move_intersection_sr(check_first,(currow+1)*TILES_PER_ROW-1,selection_left,selection_top,selection_width,selection_height);
5977
5978 for(++currow; currow<endrow; currow++)
5979 {
5980 accum |= move_intersection_sr(currow*TILES_PER_ROW,(currow+1)*TILES_PER_ROW-1,selection_left,selection_top,selection_width,selection_height);
5981 }
5982
5983 accum |= move_intersection_sr(currow*TILES_PER_ROW, check_last,selection_left,selection_top,selection_width,selection_height);
5984
5985 if(accum > 0)
5986 return ti_broken;
5987
5988 return ti_none;
5989 }
5990 }
5991
5992 return move_intersection_ss(check_first, check_last, selection_top*TILES_PER_ROW+selection_left, (selection_top+selection_height-1)*TILES_PER_ROW+selection_left+selection_width-1);
5993 }
5994
5995 //rectangular check and rectangular selection
5996 int32_t move_intersection_rr(int32_t check_left, int32_t check_top, int32_t check_width, int32_t check_height, int32_t selection_left, int32_t selection_top, int32_t selection_width, int32_t selection_height)
5997 {
5998 if((check_left>=selection_left) &&
5999 (check_left+check_width<=selection_left+selection_width) &&
6000 (check_top>=selection_top) &&
6001 (check_top+check_height<=selection_top+selection_height))
6002 {
6003 return ti_encompass;
6004 }
6005 else
6006 {
6007 for(int32_t i=check_top; i<check_top+check_height; ++i)
6008 {
6009 if(move_intersection_rs(selection_left, selection_top, selection_width, selection_height, i*TILES_PER_ROW+check_left, i*TILES_PER_ROW+check_left+check_width-1)!=ti_none)
6010 {
6011 return ti_broken;
6012 }
6013 }
6014 }
6015
6016 return ti_none;
6017 }
6018
6019
6020
6021
6022 static DIALOG move_textbox_list_dlg[] =
6023 {
6024 // (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp)
6025 12 { jwin_win_proc, 0, 0, 300, 212, vc(14), vc(1), 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6026 12 { jwin_ctext_proc, 150, 18, 0, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "", NULL, NULL },
6027 12 { jwin_ctext_proc, 150, 28, 0, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "", NULL, NULL },
6028 12 { jwin_textbox_proc, 12, 40, 277, 138, jwin_pal[jcTEXTFG], jwin_pal[jcTEXTBG], 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6029 12 { jwin_button_proc, 80, 185, 61, 21, vc(14), vc(1), 13, D_EXIT, 0, 0, (void *) "OK", NULL, NULL },
6030 12 { jwin_button_proc, 160, 185, 61, 21, vc(14), vc(1), 13, D_EXIT, 0, 0, (void *) "Cancel", NULL, NULL },
6031 12 { d_timer_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6032 12 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6033 };
6034
6035 bool popup_move_textbox_dlg(string const& msg, char* textbox, char const* title)
6036 {
6037 char buf1[512] = {0};
6038 char buf2[512] = {0};
6039 large_dialog(move_textbox_list_dlg);
6040 DIALOG& tbox = move_textbox_list_dlg[3];
6041 {
6042 FONT* f = tbox.dp2 ? (FONT*)tbox.dp2 : get_custom_font(CFONT_GUI);
6043 int indx = 0, word_indx = 0;
6044 for(char c : msg)
6045 {
6046 if(c == ' ' || c == '\n')
6047 word_indx = indx;
6048 buf1[indx++] = c;
6049 if(c == '\n' || text_length(f, buf1) >= tbox.w)
6050 {
6051 buf1[word_indx] = 0;
6052 strcpy(buf2, msg.c_str()+word_indx+1);
6053 break;
6054 }
6055 }
6056 }
6057
6058 move_textbox_list_dlg[0].dp = (void*)title;
6059 move_textbox_list_dlg[0].dp2 = get_zc_font(font_lfont);
6060 move_textbox_list_dlg[1].dp = buf1;
6061 move_textbox_list_dlg[2].dp = buf2;
6062 tbox.dp = textbox;
6063 tbox.d2 = 0;
6064 auto tby = tbox.y;
6065 auto tbh = tbox.h;
6066 if(!buf2[0])
6067 {
6068 auto diff = move_textbox_list_dlg[2].h;
6069 tbox.y -= diff;
6070 tbox.h += diff;
6071 }
6072
6073 int32_t ret=do_zqdialog(move_textbox_list_dlg,2);
6074 position_mouse_z(0);
6075 tbox.y = tby;
6076 tbox.h = tbh;
6077
6078 return ret == 4;
6079 }
6080
6081 int32_t quick_select_3(int32_t a, int32_t b, int32_t c, int32_t d)
6082 {
6083 return a==0?b:a==1?c:d;
6084 }
6085
6086 bool TileMoveList::process(std::unique_ptr<BaseTileRef>& ref, TileMoveProcess const& proc, bool is_dest)
6087 {
6088 TileRefCombo* combo_ref = dynamic_cast<TileRefCombo*>(ref.get());
6089 int i = ti_none;
6090 auto t = ref->getTile() + ref->offset();
6091
6092 if(combo_ref)
6093 {
6094 if(proc.rect)
6095 i=move_intersection_sr(*combo_ref->combo, proc._l, proc._t, proc._w, proc._h);
6096 else i=move_intersection_ss(*combo_ref->combo, proc._first, proc._last);
6097 }
6098 else if(proc.rect)
6099 {
6100 if(ref->h > 1)
6101 i=move_intersection_rr(TILECOL(t), TILEROW(t), ref->w, ref->h, proc._l, proc._t, proc._w, proc._h);
6102 else i=move_intersection_sr(t, t+ref->w-1, proc._l, proc._t, proc._w, proc._h);
6103 }
6104 else
6105 {
6106 if(ref->h > 1)
6107 i=move_intersection_rs(TILECOL(t), TILEROW(t), ref->w, ref->h, proc._first, proc._last);
6108 else i=move_intersection_ss(t, t+ref->w-1, proc._first, proc._last);
6109 }
6110
6111 bool in = i != ti_none, out = i != ti_encompass;
6112 for(size_t q = 0; !(in&&out) && q < ref->extra_rects.size(); ++q)
6113 {
6114 auto [ex_t,ex_w,ex_h] = ref->extra_rects[q];
6115 if(proc.rect)
6116 i = move_intersection_rr(TILECOL(t+ex_t), TILEROW(t+ex_t), ex_w, ex_h, proc._l, proc._t, proc._w, proc._h);
6117 else i = move_intersection_rs(TILECOL(t+ex_t), TILEROW(t+ex_t), ex_w, ex_h, proc._first, proc._last);
6118 if(i != ti_none)
6119 in = true;
6120 if(i != ti_encompass)
6121 out = true;
6122 }
6123 i = in ? (out ? ti_broken : ti_encompass) : ti_none;
6124
6125 if(i != ti_none && ref->getTile() != 0)
6126 {
6127 if(mode == Mode::CHECK_ALL)
6128 {
6129 move_refs.emplace_back(std::move(ref));
6130 return true;
6131 }
6132 else if(i==ti_broken || is_dest || (i==ti_encompass && ref->no_move))
6133 {
6134 if(warning_flood || warning_list.tellp() >= 65000)
6135 {
6136 if(!warning_flood)
6137 warning_list << "...\n...\n...\nmany others";
6138 warning_flood = true;
6139 }
6140 else
6141 warning_list << ref->name << '\n';
6142 }
6143 else if(i==ti_encompass)
6144 {
6145 move_refs.emplace_back(std::move(ref));
6146 return true;
6147 }
6148 }
6149 return false;
6150 }
6151
6152 bool TileMoveList::check_prot()
6153 {
6154 if(!TileProtection)
6155 return true;
6156 auto ret = !warning_list.tellp() || popup_move_textbox_dlg(msg, warning_list.str().data(), "Tile Warning");
6157
6158 warning_flood = false;
6159 warning_list.clear();
6160
6161 return ret;
6162 }
6163
6164 void TileMoveList::add_diff(int diff)
6165 {
6166 for(auto& ref : move_refs)
6167 ref->addTile(diff);
6168 }
6169
6170 //from 'combo.h'
6171 bool ComboMoveList::process(std::unique_ptr<BaseComboRef>& ref, ComboMoveProcess const& proc, bool is_dest)
6172 {
6173 int i = ti_none;
6174 auto c = ref->getCombo();
6175
6176 if(ref->no_move)
6177 processed_combos[c] = true;
6178 else processed_combos[c]; //inserts element if does not exist
6179 i = move_intersection_ss(c, c, proc._first, proc._last);
6180
6181 if(i != ti_none && ref->getCombo() != 0)
6182 {
6183 if(i==ti_broken || is_dest || (i==ti_encompass && ref->no_move))
6184 {
6185 if(ComboProtection)
6186 {
6187 if(warning_flood || warning_list.tellp() >= 65000)
6188 {
6189 if(!warning_flood)
6190 warning_list << "...\n...\n...\nmany others";
6191 warning_flood = true;
6192 }
6193 else
6194 warning_list << ref->name << '\n';
6195 }
6196 }
6197 else if(i==ti_encompass)
6198 {
6199 move_refs.emplace_back(std::move(ref));
6200 return true;
6201 }
6202 }
6203 return false;
6204 }
6205
6206 bool ComboMoveList::check_prot()
6207 {
6208 if(!ComboProtection)
6209 return true;
6210 vector<set<int> const*> subset = combo_links.subset(processed_combos);
6211 bool subset_header = false;
6212 for(int q = 0; q < 2; ++q)
6213 {
6214 bool is_dest = (q==1);
6215 if(!is_dest && !source_process)
6216 continue;
6217 ComboMoveProcess const& proc = is_dest ? dest_process : *source_process;
6218 for(auto it = subset.begin(); it != subset.end();)
6219 {
6220 auto s = *it;
6221 if(warning_flood || warning_list.tellp() >= 65000)
6222 {
6223 if(!warning_flood)
6224 warning_list << "...\n...\n...\nmany others";
6225 warning_flood = true;
6226 break;
6227 }
6228 set<int> in_set, out_set;
6229 bool no_move = is_dest;
6230 for(int c : *s)
6231 {
6232 int i = move_intersection_ss(c, c, proc._first, proc._last);
6233 if(i != ti_none)
6234 in_set.insert(c);
6235 if(i != ti_encompass)
6236 out_set.insert(c);
6237 if(!no_move)
6238 {
6239 auto it = processed_combos.find(c);
6240 if(it != processed_combos.end() && it->second)
6241 no_move = true;
6242 }
6243 }
6244 int i = in_set.empty() ? ti_none : (out_set.empty() ? ti_encompass : ti_broken);
6245 if(i == ti_encompass && !no_move)
6246 {
6247 it = subset.erase(it);
6248 continue;
6249 }
6250 if(i == ti_none)
6251 {
6252 ++it;
6253 continue;
6254 }
6255
6256 if(!subset_header)
6257 {
6258 subset_header = true;
6259 warning_list << "===== Broken Relative Combo Groups =====\n";
6260 }
6261 bool comma = false;
6262 warning_list << "In(";
6263 for(int c : in_set)
6264 {
6265 if(comma)
6266 warning_list << ",";
6267 else comma = true;
6268 warning_list << c;
6269 }
6270 warning_list << "),Out(";
6271 comma = false;
6272 for(int c : out_set)
6273 {
6274 if(comma)
6275 warning_list << ",";
6276 else comma = true;
6277 warning_list << c;
6278 }
6279 warning_list << ")\n";
6280 it = subset.erase(it);
6281 }
6282 }
6283 auto ret = !warning_list.tellp() || popup_move_textbox_dlg(msg, warning_list.str().data(), "Combo Warning");
6284
6285 processed_combos.clear();
6286 warning_flood = false;
6287 warning_list.clear();
6288
6289 return ret;
6290 }
6291
6292 void ComboMoveList::add_diff(int diff)
6293 {
6294 for(auto& ref : move_refs)
6295 ref->addCombo(diff);
6296 }
6297
6298 static void collect_subscreen_tiles(SubscrWidget& widget, TileMoveList& list)
6299 {
6300 if (auto w = dynamic_cast<SW_2x2Frame*>(&widget))
6301 {
6302 list.add_tile(&w->tile, 2, 2, "2x2 Frame");
6303 }
6304 else if (auto w = dynamic_cast<SW_TriFrame*>(&widget))
6305 {
6306 list.add_tile(&w->frame_tile, 6, 3, "McGuffin Frame - Frame");
6307 list.add_tile(&w->piece_tile, "McGuffin Frame - Piece");
6308 }
6309 else if (auto w = dynamic_cast<SW_McGuffin*>(&widget))
6310 {
6311 list.add_tile(&w->tile, "McGuffin Piece");
6312 }
6313 else if (auto w = dynamic_cast<SW_TileBlock*>(&widget))
6314 {
6315 list.add_tile(&w->tile, w->w, w->h, "TileBlock");
6316 }
6317 else if (auto w = dynamic_cast<SW_MiniTile*>(&widget))
6318 {
6319 if (w->tile == -1)
6320 return;
6321
6322 list.add_tile(&w->tile, "MiniTile");
6323 }
6324 else if (auto w = dynamic_cast<SW_GaugePiece*>(&widget))
6325 {
6326 int fr = w->frames ? w->frames : 1;
6327 fr = fr * (1+(w->get_per_container()/(w->unit_per_frame+1)));
6328 if(!(w->flags&SUBSCR_GAUGE_FULLTILE))
6329 fr = (fr/4_zf).getCeil();
6330
6331 for(auto q = 0; q < 4; ++q)
6332 {
6333 list.add_tile(&w->mts[q].mt_tile, fr, 1, fmt::format("Gauge Tile {}", q));
6334 }
6335 }
6336 }
6337
6338 static void collect_subscreen_tiles(SubscrPage& page, TileMoveList& list)
6339 {
6340 for(auto q = 0; q < page.contents.size(); ++q)
6341 {
6342 size_t indx = list.move_refs.size();
6343 collect_subscreen_tiles(*page.contents[q], list);
6344 for(; indx < list.move_refs.size(); ++indx)
6345 {
6346 auto& ref = list.move_refs[indx];
6347 ref->name = fmt::format("Widget {} - {}", q, ref->name);
6348 }
6349 }
6350 }
6351
6352 static void collect_subscreen_tiles(ZCSubscreen& subscreen, TileMoveList& list)
6353 {
6354 for (auto q = 0; q < subscreen.pages.size(); ++q)
6355 {
6356 size_t indx = list.move_refs.size();
6357 collect_subscreen_tiles(subscreen.pages[q], list);
6358 for(; indx < list.move_refs.size(); ++indx)
6359 {
6360 auto& ref = list.move_refs[indx];
6361 ref->name = fmt::format("Page {} - {}", q, ref->name);
6362 }
6363 }
6364 }
6365
6366 bool _handle_tile_move(TileMoveProcess dest_process, optional<TileMoveProcess> source_process, int diff, TileMoveUndo* on_undo = nullptr, std::function<void(int32_t)> every_proc = nullptr, TileMoveList::Mode mode = TileMoveList::Mode::MOVE)
6367 {
6368 bool BSZ2 = get_qr(qr_BSZELDA);
6369 bool move = source_process.has_value();
6370 TileMoveUndo local_undo;
6371 TileMoveUndo& storage = on_undo ? *on_undo : local_undo;
6372 auto& vec = storage.vec;
6373 storage.diff = diff;
6374 storage.state = false;
6375
6376 //Combos
6377 {
6378 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6379 dest_process, source_process, mode,
6380 move
6381 ? "The tiles used by the following combos will be partially cleared by the move."
6382 : "The tiles used by the following combos will be partially or completely overwritten by this process."
6383 ));
6384 for(int32_t q = 0; q < MAXCOMBOS; ++q)
6385 {
6386 auto& cmb = combobuf[q];
6387 auto lbl = fmt::format("Combo {}{}", q, cmb.label.empty() ? ""
6388 : fmt::format(" ({})", cmb.label));
6389 movelist->add_combo(&cmb, lbl);
6390
6391 //type-specific
6392 char const* type_name = ZI.getComboTypeName(cmb.type);
6393 switch(cmb.type)
6394 {
6395 case cSPOTLIGHT:
6396 {
6397 if(!(cmb.usrflags & cflag1))
6398 break;
6399 movelist->add_tile_10k(&cmb.attributes[0], 16, 1, fmt::format("{} - Type '{}' - Beam Tiles", lbl, type_name));
6400 break;
6401 }
6402 }
6403 }
6404 if(!every_proc && !movelist->check_prot())
6405 return false;
6406 }
6407 //Items
6408 {
6409 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6410 dest_process, source_process, mode,
6411 move
6412 ? "The tiles used by the following items will be partially cleared by the move."
6413 : "The tiles used by the following items will be partially or completely overwritten by this process."
6414 ));
6415 build_bii_list(false);
6416 for(int32_t u=0; u<MAXITEMS; u++)
6417 {
6418 auto id = bii[u].i;
6419 itemdata& itm = itemsbuf[id];
6420 if(itm.type == itype_bottle)
6421 {
6422 vector<std::tuple<int,int,int>> rects;
6423 auto fr = itm.frames;
6424 for(int q = 0; q < NUM_BOTTLE_TYPES; ++q)
6425 {
6426 bottletype const& bt = QMisc.bottle_types[q];
6427 if(bt.is_blank())
6428 continue;
6429 rects.emplace_back(fr+q*fr, fr, 1);
6430 }
6431 movelist->add_tile(&itm.tile, fr, 1, fmt::format("Item {}", id),
6432 false, 0, 0, rects);
6433 }
6434 else movelist->add_tile(&itm.tile, itm.frames, 1, fmt::format("Item {}", id));
6435 }
6436 if(!every_proc && !movelist->check_prot())
6437 return false;
6438 }
6439 //Weapon sprites
6440 {
6441 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6442 dest_process, source_process, mode,
6443 move
6444 ? "The tiles used by the following weapons will be partially cleared by the move."
6445 : "The tiles used by the following weapons will be partially or completely overwritten by this process."
6446 ));
6447 build_biw_list();
6448
6449 for(int32_t u=0; u<MAXWPNS; u++)
6450 {
6451 bool ignore_frames=false;
6452 int32_t m=0;
6453
6454 auto id = biw[u].i;
6455 auto& wpn = wpnsbuf[id];
6456
6457 switch(biw[u].i)
6458 {
6459 case wSWORD:
6460 case wWSWORD:
6461 case wMSWORD:
6462 case wXSWORD:
6463 m=3+((wpnsbuf[biw[u].i].type==3)?1:0);
6464 break;
6465
6466 case wSWORDSLASH:
6467 case wWSWORDSLASH:
6468 case wMSWORDSLASH:
6469 case wXSWORDSLASH:
6470 m=4;
6471 break;
6472
6473 case iwMMeter:
6474 m=9;
6475 break;
6476
6477 case wBRANG:
6478 case wMBRANG:
6479 case wFBRANG:
6480 m=BSZ2?1:3;
6481 break;
6482
6483 case wBOOM:
6484 case wSBOOM:
6485 case ewBOOM:
6486 case ewSBOOM:
6487 ignore_frames=true;
6488 m=2;
6489 break;
6490
6491 case wWAND:
6492 m=1;
6493 break;
6494
6495 case wMAGIC:
6496 m=1;
6497 break;
6498
6499 case wARROW:
6500 case wSARROW:
6501 case wGARROW:
6502 case ewARROW:
6503 m=1;
6504 break;
6505
6506 case wHAMMER:
6507 m=8;
6508 break;
6509
6510 case wHSHEAD:
6511 m=1;
6512 break;
6513
6514 case wHSCHAIN_H:
6515 m=1;
6516 break;
6517
6518 case wHSCHAIN_V:
6519 m=1;
6520 break;
6521
6522 case wHSHANDLE:
6523 m=1;
6524 break;
6525
6526 case iwDeath:
6527 if(get_qr(qr_HARDCODED_ENEMY_ANIMS))
6528 {
6529 ignore_frames = true;
6530 m=BSZ2?4:2;
6531 }
6532 break;
6533
6534 case iwSpawn:
6535 if(get_qr(qr_HARDCODED_ENEMY_ANIMS))
6536 {
6537 ignore_frames = true;
6538 m=3;
6539 }
6540 break;
6541 }
6542
6543 movelist->add_tile(&wpn.tile, zc_max((ignore_frames?0:wpn.frames),1)+m,
6544 1, fmt::format("{} {}", biw[u].s, id));
6545
6546 //Tile 54+55 are "Impact (not shown in sprite list)", for u==3 "Arrow" and u==9 "Boomerang"
6547 //...these can't be updated by a move.
6548 if((u==3)||(u==9))
6549 {
6550 static int32_t impact_tiles[2] = {54,54};
6551 auto& tile = impact_tiles[u==3 ? 0 : 1];
6552 tile = 54; //dummy tile, ensure it's correct
6553 movelist->add_tile(&tile, 2, 1,
6554 fmt::format("{} Impact (not shown in sprite list)",(u==3)?"Arrow":"Boomerang"),
6555 true);
6556 }
6557 }
6558 if(!every_proc && !movelist->check_prot())
6559 return false;
6560 }
6561 //Hero sprites
6562 {
6563 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6564 dest_process, source_process, mode,
6565 move
6566 ? "The tiles used by the following Hero sprites will be partially cleared by the move."
6567 : "The tiles used by the following Hero sprites will be partially or completely overwritten by this process."
6568 ));
6569 {
6570 int32_t a_style=(zinit.heroAnimationStyle);
6571 #define ADD_HERO_SPRITE(ref_sprite, frames, name) \
6572 do \
6573 { \
6574 movelist->add_tile(&ref_sprite[spr_tile], \
6575 (ref_sprite[spr_extend] < 2 ? 1 : 2) * frames, \
6576 ref_sprite[spr_extend] < 1 ? 1 : 2, \
6577 name, false, \
6578 ref_sprite[spr_extend] < 2 ? 0 : -1, \
6579 ref_sprite[spr_extend] < 1 ? 0 : -1); \
6580 } while(false)
6581 // + (ref_sprite[spr_extend] < 2 ? 0 : 1) //this was on some of the 'width's before... but doesn't make sense?
6582
6583 for(int32_t i=0; i<4; ++i)
6584 {
6585 ADD_HERO_SPRITE(walkspr[i], quick_select_3(a_style, (i==0?1:2), 3, 9), fmt::format("Walking ({})", dirstr_proper[i]));
6586 }
6587
6588 for(int32_t i=0; i<4; ++i)
6589 {
6590 ADD_HERO_SPRITE(slashspr[i], quick_select_3(a_style, 1, 1, 6), fmt::format("Slashing ({})", dirstr_proper[i]));
6591 }
6592
6593 for(int32_t i=0; i<4; ++i)
6594 {
6595 ADD_HERO_SPRITE(stabspr[i], quick_select_3(a_style, 1, 1, 3), fmt::format("Stabbing ({})", dirstr_proper[i]));
6596 }
6597
6598 for(int32_t i=0; i<4; ++i)
6599 {
6600 ADD_HERO_SPRITE(poundspr[i], quick_select_3(a_style, 1, 1, 3), fmt::format("Pounding ({})", dirstr_proper[i]));
6601 }
6602
6603 for(int32_t i=0; i<2; ++i)
6604 {
6605 ADD_HERO_SPRITE(holdspr[0][i], 1, fmt::format("Hold (Land, {}-hand)", i+1));
6606 }
6607
6608 ADD_HERO_SPRITE(castingspr, 1, "Casting");
6609
6610 for(int32_t i=0; i<4; ++i)
6611 {
6612 ADD_HERO_SPRITE(floatspr[i], quick_select_3(a_style, 2, 3, 4), fmt::format("Floating ({})", dirstr_proper[i]));
6613 }
6614
6615 for(int32_t i=0; i<4; ++i)
6616 {
6617 ADD_HERO_SPRITE(swimspr[i], quick_select_3(a_style, 2, 3, 4), fmt::format("Swimming ({})", dirstr_proper[i]));
6618 }
6619
6620 for(int32_t i=0; i<4; ++i)
6621 {
6622 ADD_HERO_SPRITE(divespr[i], quick_select_3(a_style, 2, 3, 4), fmt::format("Diving ({})", dirstr_proper[i]));
6623 }
6624
6625 for(int32_t i=0; i<2; ++i)
6626 {
6627 ADD_HERO_SPRITE(holdspr[1][i], 1, fmt::format("Hold (Water, {}-hand)", i));
6628 }
6629
6630 for(int32_t i=0; i<4; ++i)
6631 {
6632 ADD_HERO_SPRITE(jumpspr[i], 3, fmt::format("Jumping ({})", dirstr_proper[i]));
6633 }
6634
6635 for(int32_t i=0; i<4; ++i)
6636 {
6637 ADD_HERO_SPRITE(chargespr[i], quick_select_3(a_style, 2, 3, 9), fmt::format("Charging ({})", dirstr_proper[i]));
6638 }
6639 for(int32_t i=0; i<4; ++i)
6640 {
6641 ADD_HERO_SPRITE(revslashspr[i], quick_select_3(a_style, 1, 1, 6), fmt::format("Slash 2 ({})", dirstr_proper[i]));
6642 }
6643 for(int32_t i=0; i<4; ++i)
6644 {
6645 ADD_HERO_SPRITE(fallingspr[i], 7, fmt::format("Falling ({})", dirstr_proper[i]));
6646 }
6647 for(int32_t i=0; i<4; ++i)
6648 {
6649 ADD_HERO_SPRITE(liftingspr[i], liftingspr[i][spr_frames], fmt::format("Lifting ({})", dirstr_proper[i]));
6650 }
6651 for(int32_t i=0; i<4; ++i)
6652 {
6653 ADD_HERO_SPRITE(liftingwalkspr[i], quick_select_3(a_style, (i==0?1:2), 3, 9), fmt::format("Lift-Walking ({})", dirstr_proper[i]));
6654 }
6655 for(int32_t i=0; i<4; ++i)
6656 {
6657 ADD_HERO_SPRITE(drowningspr[i], quick_select_3(a_style, 2, 3, 3), fmt::format("Drowning ({})", dirstr_proper[i]));
6658 }
6659 for(int32_t i=0; i<4; ++i)
6660 {
6661 ADD_HERO_SPRITE(drowning_lavaspr[i], quick_select_3(a_style, 2, 3, 3), fmt::format("Lava Drowning ({})", dirstr_proper[i]));
6662 }
6663 for(int32_t i=0; i<4; ++i)
6664 {
6665 ADD_HERO_SPRITE(sideswimspr[i], quick_select_3(a_style, 2, 3, 3), fmt::format("Side-Swimming ({})", dirstr_proper[i]));
6666 }
6667 //69
6668 for(int32_t i=0; i<4; ++i)
6669 {
6670 ADD_HERO_SPRITE(sideswimslashspr[i], quick_select_3(a_style, 1, 1, 6), fmt::format("Side-Swim Slash ({})", dirstr_proper[i]));
6671 }
6672 //73
6673 for(int32_t i=0; i<4; ++i)
6674 {
6675 ADD_HERO_SPRITE(sideswimstabspr[i], quick_select_3(a_style, 1, 1, 3), fmt::format("Side-Swim Stab ({})", dirstr_proper[i]));
6676 }
6677 //77
6678 for(int32_t i=0; i<4; ++i)
6679 {
6680 ADD_HERO_SPRITE(sideswimpoundspr[i], quick_select_3(a_style, 1, 1, 3), fmt::format("Side-Swim Pound ({})", dirstr_proper[i]));
6681 }
6682 //81
6683 for(int32_t i=0; i<4; ++i)
6684 {
6685 ADD_HERO_SPRITE(sideswimchargespr[i], quick_select_3(a_style, 2, 3, 9), fmt::format("Side-Swim Charging ({})", dirstr_proper[i]));
6686 }
6687 //85
6688 ADD_HERO_SPRITE(sideswimholdspr[spr_hold1], 1, "Hold (Side-Water, 1-hand)");
6689 ADD_HERO_SPRITE(sideswimholdspr[spr_hold2], 1, "Hold (Side-Water, 2-hand)");
6690 ADD_HERO_SPRITE(sideswimcastingspr, 1, "Side-Swim Casting");
6691 for(int32_t i=0; i<4; ++i)
6692 {
6693 ADD_HERO_SPRITE(sidedrowningspr[i], quick_select_3(a_style, 2, 3, 3), fmt::format("Side-Swim Drowning ({})", dirstr_proper[i]));
6694 }
6695 //91
6696 }
6697 if(!every_proc && !movelist->check_prot())
6698 return false;
6699 }
6700 //Map Styles
6701 {
6702 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6703 dest_process, source_process, mode,
6704 move
6705 ? "The tiles used by the following map styles will be partially cleared by the move."
6706 : "The tiles used by the following map styles will be partially or completely overwritten by this process."
6707 ));
6708 movelist->add_tile(&QMisc.colors.blueframe_tile, 2, 2, "Frame");
6709 movelist->add_tile(&QMisc.colors.HCpieces_tile, zinit.hcp_per_hc, 1, "Heart Container Piece");
6710 movelist->add_tile(&QMisc.colors.triforce_tile, BSZ2?2:1, BSZ2?3:1, "McGuffin Fragment");
6711 movelist->add_tile(&QMisc.colors.triframe_tile, BSZ2?7:6, BSZ2?7:3, "McGuffin Frame");
6712 movelist->add_tile(&QMisc.colors.overworld_map_tile, 5, 3, "Overworld Map");
6713 movelist->add_tile(&QMisc.colors.dungeon_map_tile, 5, 3, "Dungeon Map");
6714 if(!every_proc && !movelist->check_prot())
6715 return false;
6716 }
6717 //Game Icons
6718 {
6719 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6720 dest_process, source_process, mode,
6721 move
6722 ? "The tiles used by the following game icons will be partially cleared by the move."
6723 : "The tiles used by the following game icons will be partially or completely overwritten by this process."
6724 ));
6725 for(int32_t u=0; u<4; u++)
6726 movelist->add_tile(&QMisc.icons[u], fmt::format("Game Icon {}", u));
6727 if(!every_proc && !movelist->check_prot())
6728 return false;
6729 }
6730 //DMaps
6731 {
6732 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6733 dest_process, source_process, mode,
6734 move
6735 ? "The tiles used by the following dmaps will be partially cleared by the move."
6736 : "The tiles used by the following dmaps will be partially or completely overwritten by this process."
6737 ));
6738 for(int32_t u=0; u<MAXDMAPS; u++)
6739 {
6740 auto& dm = DMaps[u];
6741 movelist->add_tile(&dm.minimap_tile[0], 5, 3, fmt::format("DMap {} - Minimap (Empty)", u));
6742 movelist->add_tile(&dm.minimap_tile[1], 5, 3, fmt::format("DMap {} - Minimap (Filled)", u));
6743 movelist->add_tile(&dm.largemap_tile[0], BSZ2?7:9, 5, fmt::format("DMap {} - Large Map (Empty)", u));
6744 movelist->add_tile(&dm.largemap_tile[1], BSZ2?7:9, 5, fmt::format("DMap {} - Large Map (Filled)", u));
6745 }
6746 if(!every_proc && !movelist->check_prot())
6747 return false;
6748 }
6749 //Enemies
6750 {
6751 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6752 dest_process, source_process, mode,
6753 move
6754 ? "The tiles used by the following enemies will be partially cleared by the move."
6755 : "The tiles used by the following enemies will be partially or completely overwritten by this process."
6756 ));
6757 build_bie_list(false);
6758 bool newtiles=get_qr(qr_NEWENEMYTILES)!=0;
6759 for(int u=0; u<eMAXGUYS; u++)
6760 {
6761 guydata& enemy=guysbuf[bie[u].i];
6762 bool darknut=false;
6763 bool gleeok=false;
6764
6765 if(enemy.type==eeWALK && ((enemy.flags&(guy_shield_back|guy_shield_front|guy_shield_left|guy_shield_right))!=0))
6766 darknut=true;
6767 else if(enemy.type==eeGLEEOK)
6768 gleeok=true;
6769 else if (enemy.type == eePATRA)
6770 {
6771 if (!get_qr(qr_PATRAS_USE_HARDCODED_OFFSETS))
6772 {
6773 darknut=true; //uses the same logic no need for separate variables!
6774 }
6775 }
6776
6777 // Dummied out enemies
6778 if(bie[u].i>=eOCTO1S && bie[u].i<e177)
6779 {
6780 if(old_guy_string[bie[u].i][strlen(old_guy_string[bie[u].i])-1]==' ')
6781 {
6782 continue;
6783 }
6784 }
6785
6786 if(newtiles)
6787 {
6788 if(enemy.e_tile==0)
6789 {
6790 continue;
6791 }
6792
6793 vector<std::tuple<int,int,int>> rects;
6794
6795 if(darknut) //or anything that uses S. Tile for with new tiles
6796 {
6797 if (enemy.s_tile != 0)
6798 {
6799 movelist->add_tile(&enemy.s_tile, enemy.s_width, enemy.s_height, fmt::format("Enemy {} ({}) 'Special'", u, bie[u].s));
6800 }
6801 }
6802 else if (gleeok)
6803 {
6804 for (int32_t j = 0; j < enemy.attributes[4]; ++j)
6805 {
6806 rects.emplace_back(enemy.attributes[5] + (enemy.attributes[6]*j), 4, 1);
6807 }
6808 rects.emplace_back(enemy.attributes[7], 4, 1);
6809 rects.emplace_back(enemy.attributes[8], 4, 1);
6810 }
6811 movelist->add_tile(&enemy.e_tile, enemy.e_width, enemy.e_height, fmt::format("Enemy {} ({}) 'New'", u, bie[u].s),
6812 false, 0, 0, rects);
6813
6814 }
6815 else
6816 {
6817 if(enemy.tile==0)
6818 {
6819 continue;
6820 }
6821 movelist->add_tile(&enemy.tile, enemy.width, enemy.height, fmt::format("Enemy {} ({}) 'Old'", u, bie[u].s));
6822
6823 if(enemy.s_tile!=0)
6824 {
6825 movelist->add_tile(&enemy.s_tile, enemy.s_width, enemy.s_height, fmt::format("Enemy {} ({}) 'Special'", u, bie[u].s));
6826 }
6827 }
6828 }
6829 if(!every_proc && !movelist->check_prot())
6830 return false;
6831 }
6832 //Subscreens
6833 {
6834 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6835 dest_process, source_process, mode,
6836 move
6837 ? "The tiles used by the following subscreen widgets will be partially cleared by the move."
6838 : "The tiles used by the following subscreen widgets will be partially or completely overwritten by this process."
6839 ));
6840
6841 for(auto q = 0; q < subscreens_active.size(); ++q)
6842 {
6843 size_t indx = movelist->move_refs.size();
6844 collect_subscreen_tiles(subscreens_active[q], *movelist.get());
6845 for(; indx < movelist->move_refs.size(); ++indx)
6846 {
6847 auto& ref = movelist->move_refs[indx];
6848 ref->name = fmt::format("Active Subscr {} - {}", q, ref->name);
6849 }
6850 }
6851 for(auto q = 0; q < subscreens_passive.size(); ++q)
6852 {
6853 size_t indx = movelist->move_refs.size();
6854 collect_subscreen_tiles(subscreens_passive[q], *movelist.get());
6855 for(; indx < movelist->move_refs.size(); ++indx)
6856 {
6857 auto& ref = movelist->move_refs[indx];
6858 ref->name = fmt::format("Passive Subscr {} - {}", q, ref->name);
6859 }
6860 }
6861 for(auto q = 0; q < subscreens_overlay.size(); ++q)
6862 {
6863 size_t indx = movelist->move_refs.size();
6864 collect_subscreen_tiles(subscreens_overlay[q], *movelist.get());
6865 for(; indx < movelist->move_refs.size(); ++indx)
6866 {
6867 auto& ref = movelist->move_refs[indx];
6868 ref->name = fmt::format("Overlay Subscr {} - {}", q, ref->name);
6869 }
6870 }
6871 for(auto q = 0; q < subscreens_map.size(); ++q)
6872 {
6873 size_t indx = movelist->move_refs.size();
6874 collect_subscreen_tiles(subscreens_map[q], *movelist.get());
6875 for(; indx < movelist->move_refs.size(); ++indx)
6876 {
6877 auto& ref = movelist->move_refs[indx];
6878 ref->name = fmt::format("Map Subscr {} - {}", q, ref->name);
6879 }
6880 }
6881 if(!every_proc && !movelist->check_prot())
6882 return false;
6883 }
6884 //Strings
6885 {
6886 auto& movelist = vec.emplace_back(std::make_unique<TileMoveList>(
6887 dest_process, source_process, mode,
6888 move
6889 ? "The tiles used by the following strings will be partially cleared by the move."
6890 : "The tiles used by the following strings will be partially or completely overwritten by this process."
6891 ));
6892 for(size_t q = 0; q < msg_count; ++q)
6893 {
6894 MsgStr& str = MsgStrings[q];
6895 std::string text = str.serialize();
6896 bool fulltile = str.stringflags & STRINGFLAG_FULLTILE;
6897 movelist->add_tile(&str.tile, fulltile ? (str.w/16_zf).getCeil() : 2,
6898 fulltile ? (str.h/16_zf).getCeil() : 2, fmt::format("{} (BG): '{}'", q, util::snip(text,100)));
6899 movelist->add_tile(&str.portrait_tile, str.portrait_tw, str.portrait_th,
6900 fmt::format("{} (Port.): '{}'", q, util::snip(text,100)));
6901 }
6902 if(!every_proc && !movelist->check_prot())
6903 return false;
6904 }
6905
6906 if(source_process) //Apply the 'diff' value to all moved tiles
6907 storage.redo();
6908 if(every_proc)
6909 for(auto &list : vec)
6910 for(auto &ref : list->move_refs)
6911 ref->forEach(every_proc);
6912 return true;
6913 }
6914 bool handle_tile_move(TileMoveProcess dest_process)
6915 {
6916 return _handle_tile_move(dest_process, nullopt, 0);
6917 }
6918 bool handle_tile_move(TileMoveProcess dest_process, TileMoveProcess source_process, int diff, TileMoveUndo& on_undo)
6919 {
6920 return _handle_tile_move(dest_process, source_process, diff, &on_undo);
6921 }
6922 void for_every_used_tile(std::function<void(int32_t)> proc)
6923 {
6924 reset_combo_animations();
6925 reset_combo_animations2();
6926 TileMoveProcess all_tiles {.rect = false, ._first = 0, ._last = NEWMAXTILES-1};
6927 _handle_tile_move(all_tiles, nullopt, 0, nullptr, proc, TileMoveList::Mode::CHECK_ALL);
6928 }
6929
6930 bool _handle_combo_move(ComboMoveProcess dest_process, optional<ComboMoveProcess> source_process, int diff, ComboMoveUndo* on_undo)
6931 {
6932 bool move = source_process.has_value();
6933 ComboMoveUndo local_undo;
6934 ComboMoveUndo& storage = on_undo ? *on_undo : local_undo;
6935 auto& vec = storage.vec;
6936 auto& combo_links = storage.combo_links;
6937 storage.diff = diff;
6938 storage.state = false;
6939 //Combo relative links
6940 {
6941 for(int32_t q = 0; q < MAXCOMBOS; ++q)
6942 {
6943 newcombo& cmb = combobuf[q];
6944 for(size_t idx = 0; idx < cmb.triggers.size(); ++idx)
6945 {
6946 auto& trig = cmb.triggers[idx];
6947 if(trig.trigchange)
6948 combo_links.add_to(q, q+trig.trigchange);
6949 }
6950 bool next = cmb.flag == mfSECRETSNEXT;
6951 switch(cmb.type)
6952 {
6953 case cPOUND:
6954 case cLOCKBLOCK: case cLOCKBLOCK2:
6955 case cBOSSLOCKBLOCK: case cBOSSLOCKBLOCK2:
6956 case cCHEST: case cCHEST2:
6957 case cLOCKEDCHEST: case cLOCKEDCHEST2:
6958 case cBOSSCHEST: case cBOSSCHEST2:
6959 case cSTEP: case cSTEPSAME: case cSTEPALL: case cSTEPCOPY:
6960 case cSLASHNEXT: case cSLASHNEXTITEM: case cBUSHNEXT:
6961 case cSLASHNEXTTOUCHY: case cSLASHNEXTITEMTOUCHY: case cBUSHNEXTTOUCHY:
6962 case cTALLGRASSNEXT: case cCRUMBLE:
6963 next = true;
6964 break;
6965 case cCSWITCH: case cCSWITCHBLOCK:
6966 combo_links.add_to(q, q+cmb.attributes[0]);
6967 break;
6968 case cLIGHTTARGET:
6969 if(cmb.usrflags & cflag1)
6970 combo_links.add_to(q, q-1);
6971 else next = true;
6972 break;
6973 case cSTEPSFX:
6974 if((cmb.usrflags&(cflag1|cflag3)) == cflag1)
6975 next = true;
6976 break;
6977 }
6978 if(next)
6979 combo_links.add_to(q, q+1);
6980 }
6981 }
6982
6983 //This function is expensive! Any optimizations possible should be made. -Em
6984
6985 //OPT: Check for a 0-val preemptively, to avoid processing the fmt::format strings
6986 #define ADDC(ptr, str) \
6987 if(*ptr) movelist->add_combo(ptr, ComboProtection ? str : "");
6988 #define ADDC_10k(ptr, str) \
6989 if(*ptr) movelist->add_combo_10k(ptr, ComboProtection ? str : "");
6990 //Combos
6991 {
6992 auto& movelist = vec.emplace_back(std::make_unique<ComboMoveList>(
6993 combo_links, dest_process, source_process,
6994 move
6995 ? "The combos used by the following combos will be partially cleared by the move."
6996 : "The combos used by the following combos will be partially or completely overwritten by this process."
6997 ));
6998 for(int32_t q = 0; q < MAXCOMBOS; ++q)
6999 {
7000 newcombo& cmb = combobuf[q];
7001 auto lbl = fmt::format("{}{}", q, cmb.label.empty() ? ""
7002 : fmt::format(" ({})", cmb.label));
7003 ADDC(&cmb.nextcombo, fmt::format("{} - Combo Cycle", lbl));
7004 ADDC(&cmb.liftcmb, fmt::format("{} - Lift Combo", lbl));
7005 ADDC(&cmb.liftundercmb, fmt::format("{} - Lift Undercombo", lbl));
7006 for(auto& trig : cmb.triggers)
7007 ADDC(&trig.prompt_cid, fmt::format("{} - Triggers ButtonPrompt", lbl));
7008
7009 //type-specific
7010 char const* type_name = ZI.getComboTypeName(cmb.type);
7011 switch(cmb.type)
7012 {
7013 case cLOCKEDCHEST: case cBOSSCHEST:
7014 if(cmb.usrflags & cflag13)
7015 ADDC_10k(&cmb.attributes[2], fmt::format("{} - Type '{}' - Locked Prompt", lbl, type_name));
7016 [[fallthrough]];
7017 case cCHEST:
7018 if(cmb.usrflags & cflag13)
7019 ADDC_10k(&cmb.attributes[1], fmt::format("{} - Type '{}' - Prompt", lbl, type_name));
7020 break;
7021 case cLOCKBLOCK: case cBOSSLOCKBLOCK:
7022 if(cmb.usrflags & cflag13)
7023 {
7024 ADDC_10k(&cmb.attributes[1], fmt::format("{} - Type '{}' - Prompt", lbl, type_name));
7025 ADDC_10k(&cmb.attributes[2], fmt::format("{} - Type '{}' - Locked Prompt", lbl, type_name));
7026 }
7027 break;
7028 case cSIGNPOST:
7029 if(cmb.usrflags & cflag13)
7030 ADDC_10k(&cmb.attributes[1], fmt::format("{} - Type '{}' - Prompt", lbl, type_name));
7031 break;
7032 case cBUTTONPROMPT:
7033 if(cmb.usrflags & cflag13)
7034 ADDC_10k(&cmb.attributes[0], fmt::format("{} - Type '{}' - Prompt", lbl, type_name));
7035 break;
7036 }
7037 }
7038
7039 if(!movelist->check_prot())
7040 return false;
7041 }
7042 //Door Combo Sets
7043 {
7044 auto& movelist = vec.emplace_back(std::make_unique<ComboMoveList>(
7045 combo_links, dest_process, source_process,
7046 move
7047 ? "The combos used by the following screens will be partially cleared by the move."
7048 : "The combos used by the following screens will be partially or completely overwritten by this process."
7049 ));
7050 static const char* door_names[9] = {
7051 "Wall", "Locked", "Shuttered", "Boss", "Bombed", "Open", "Unlocked", "Open Shuttered", "Open Boss"
7052 };
7053 for(int32_t i=0; i<MAXDOORCOMBOSETS; i++)
7054 {
7055 auto& dcs = DoorComboSets[i];
7056 auto& name = DoorComboSetNames[i];
7057 for(int32_t j=0; j<9; j++)
7058 {
7059 if(j<4)
7060 {
7061 ADDC(&dcs.walkthroughcombo[j], fmt::format("{} ({}): Walk-Through {}", i, name, j));
7062
7063 if(j<3)
7064 {
7065 if(j<2)
7066 {
7067 ADDC(&dcs.bombdoorcombo_u[j], fmt::format("{} ({}): Unused? bombdoorcombo_u {}", i, name, j));
7068 ADDC(&dcs.bombdoorcombo_d[j], fmt::format("{} ({}): Unused? bombdoorcombo_d {}", i, name, j));
7069 }
7070 ADDC(&dcs.bombdoorcombo_l[j], fmt::format("{} ({}): Unused? bombdoorcombo_l {}", i, name, j));
7071 ADDC(&dcs.bombdoorcombo_r[j], fmt::format("{} ({}): Unused? bombdoorcombo_r {}", i, name, j));
7072 }
7073 }
7074
7075 for(int32_t k=0; k<6; k++)
7076 {
7077 if(k<4)
7078 {
7079 ADDC(&dcs.doorcombo_u[j][k], fmt::format("{} ({}): Top, {} #{}", i, name, door_names[j], k));
7080 ADDC(&dcs.doorcombo_d[j][k], fmt::format("{} ({}): Bottom, {} #{}", i, name, door_names[j], k));
7081 }
7082
7083 ADDC(&dcs.doorcombo_l[j][k], fmt::format("{} ({}): Left, {} #{}", i, name, door_names[j], k));
7084 ADDC(&dcs.doorcombo_r[j][k], fmt::format("{} ({}): Right, {} #{}", i, name, door_names[j], k));
7085 }
7086 }
7087 }
7088
7089 if(!movelist->check_prot())
7090 return false;
7091 }
7092 //Combo Pools
7093 {
7094 auto& movelist = vec.emplace_back(std::make_unique<ComboMoveList>(
7095 combo_links, dest_process, source_process,
7096 move
7097 ? "The combos used by the following combo pools will be partially cleared by the move."
7098 : "The combos used by the following combo pools will be partially or completely overwritten by this process."
7099 ));
7100 for(auto q = 0; q < MAXCOMBOPOOLS; ++q)
7101 {
7102 combo_pool& pool = combo_pools[q];
7103 int idx = 0;
7104 for(cpool_entry& cp : pool.combos)
7105 ADDC(&cp.cid, fmt::format("{} index {}", q, idx++));
7106 }
7107
7108 if(!movelist->check_prot())
7109 return false;
7110 }
7111 //Auto Combos
7112 {
7113 auto& movelist = vec.emplace_back(std::make_unique<ComboMoveList>(
7114 combo_links, dest_process, source_process,
7115 move
7116 ? "The combos used by the following autocombos will be partially cleared by the move."
7117 : "The combos used by the following autocombos will be partially or completely overwritten by this process."
7118 ));
7119 for (auto q = 0; q < MAXAUTOCOMBOS; ++q)
7120 {
7121 combo_auto& cauto = combo_autos[q];
7122 int idx = 0;
7123 for (autocombo_entry& ac : cauto.combos)
7124 ADDC(&ac.cid, fmt::format("{} index {}", q, idx++));
7125 ADDC(&cauto.cid_erase, fmt::format("{} Erase Combo", q));
7126 ADDC(&cauto.cid_display, fmt::format("{} Display Combo", q));
7127 }
7128
7129 if(!movelist->check_prot())
7130 return false;
7131 }
7132 //Combo Aliases
7133 {
7134 auto& movelist = vec.emplace_back(std::make_unique<ComboMoveList>(
7135 combo_links, dest_process, source_process,
7136 move
7137 ? "The combos used by the following aliases will be partially cleared by the move."
7138 : "The combos used by the following aliases will be partially or completely overwritten by this process."
7139 ));
7140 for(int32_t i=0; i<MAXCOMBOALIASES; i++)
7141 {
7142 //dimensions are 1 less than you would expect -DD
7143 int32_t count=(comboa_lmasktotal(combo_aliases[i].layermask)+1)*(combo_aliases[i].width+1)*(combo_aliases[i].height+1);
7144
7145 for(int32_t j=0; j<count; j++)
7146 {
7147 ADDC(&combo_aliases[i].combos[j], fmt::format("{} index {}", i, j));
7148 }
7149 }
7150
7151 if(!movelist->check_prot())
7152 return false;
7153 }
7154 //Favorite Combos
7155 {
7156 auto& movelist = vec.emplace_back(std::make_unique<ComboMoveList>(
7157 combo_links, dest_process, source_process,
7158 move
7159 ? "The combos used by the following favorite combos will be partially cleared by the move."
7160 : "The combos used by the following favorite combos will be partially or completely overwritten by this process."
7161 ));
7162 for(int32_t i=0; i<MAXFAVORITECOMBOS; i++)
7163 {
7164 if(favorite_combo_modes[i] != dm_normal) //don't hit pools/aliases/autos, only combos!
7165 continue;
7166 ADDC(&favorite_combos[i], fmt::format("Favorite {}", i));
7167 }
7168
7169 if(!movelist->check_prot())
7170 return false;
7171 }
7172 //Bottle Shops
7173 {
7174 auto& movelist = vec.emplace_back(std::make_unique<ComboMoveList>(
7175 combo_links, dest_process, source_process,
7176 move
7177 ? "The combos used by the following bottle shops will be partially cleared by the move."
7178 : "The combos used by the following bottle shops will be partially or completely overwritten by this process."
7179 ));
7180 for(auto q = 0; q < 256; ++q)
7181 for(auto p = 0; p < 3; ++p)
7182 ADDC(&QMisc.bottle_shop_types[q].comb[p], fmt::format("{} slot {}", q, p));
7183
7184 if(!movelist->check_prot())
7185 return false;
7186 }
7187 //Screens //EXPENSIVE! DO THIS LAST!
7188 {
7189 auto& movelist = vec.emplace_back(std::make_unique<ComboMoveList>(
7190 combo_links, dest_process, source_process,
7191 move
7192 ? "The combos used by the following screens will be partially cleared by the move."
7193 : "The combos used by the following screens will be partially or completely overwritten by this process."
7194 ));
7195
7196 for(int32_t i=0; i<map_count && i<MAXMAPS; i++)
7197 {
7198 for(int32_t j=0; j<MAPSCRS; j++)
7199 {
7200 mapscr& scr = TheMaps[i*MAPSCRS+j];
7201
7202 if(!(scr.valid&mVALID))
7203 continue;
7204
7205 ADDC(&scr.undercombo, fmt::format("{}x{:02X} - UnderCombo", i, j));
7206
7207 // Specifying the exact position is too expensive - too much string creation.
7208 std::string data_str = ComboProtection ? fmt::format("{}x{:02X} - Combo", i, j) : "";
7209 for(int32_t k=0; k<176; k++)
7210 ADDC(&scr.data[k], data_str);
7211
7212 for(int32_t k=0; k<128; k++)
7213 ADDC(&scr.secretcombo[k], fmt::format("{}x{:02X} - SecretCombo {}", i, j, k));
7214
7215 word maxffc = scr.numFFC();
7216 for(word k=0; k<maxffc; k++)
7217 {
7218 ffcdata& ffc = scr.ffcs[k];
7219 ADDC(&ffc.data, fmt::format("{}x{:02X} - FFC {}", i, j, k+1));
7220 }
7221 }
7222 }
7223
7224 if(!movelist->check_prot())
7225 return false;
7226 }
7227 if(source_process) //Apply the 'diff' value to all moved combos
7228 storage.redo();
7229 return true;
7230 }
7231
7232 bool handle_combo_move(ComboMoveProcess dest_process)
7233 {
7234 return _handle_combo_move(dest_process, nullopt, 0, nullptr);
7235 }
7236 bool handle_combo_move(ComboMoveProcess dest_process, ComboMoveProcess source_process, int diff, ComboMoveUndo& on_undo)
7237 {
7238 return _handle_combo_move(dest_process, source_process, diff, &on_undo);
7239 }
7240 void register_used_tiles()
7241 {
7242 memset(used_tile_table, 0, sizeof(used_tile_table));
7243 for_every_used_tile([&](int tile)
7244 {
7245 used_tile_table[tile] = true;
7246 });
7247 }
7248
7249 bool overlay_tiles(int32_t &tile,int32_t &tile2,int32_t &copy,int32_t &copycnt, bool rect_sel, bool move, int32_t cs, bool backwards)
7250 {
7251 bool ctrl=(CHECK_CTRL_CMD);
7252 bool copied=false;
7253 copied=overlay_tiles_united(tile,tile2,copy,copycnt,rect_sel,move,cs,backwards);
7254
7255 if(copied)
7256 {
7257 mark_save_dirty();
7258 }
7259
7260 return copied;
7261 }
7262
7263 bool overlay_tiles_united(int32_t &tile,int32_t &tile2,int32_t &copy,int32_t &copycnt, bool rect, bool move, int32_t cs, bool backwards)
7264 {
7265 bool alt=(key[KEY_ALT]||key[KEY_ALTGR]);
7266 bool shift=(key[KEY_LSHIFT] || key[KEY_RSHIFT]);
7267
7268 // if tile>tile2 then swap them
7269 if(tile>tile2)
7270 {
7271 zc_swap(tile, tile2);
7272 }
7273
7274 // alt=copy from right
7275 // shift=copy from bottom
7276
7277 int32_t copies=copycnt;
7278 int32_t dest_first=tile;
7279 int32_t dest_last=tile2;
7280 int32_t src_first=copy;
7281 int32_t src_last=copy+copies-1;
7282
7283 int32_t dest_top=0;
7284 int32_t dest_bottom=0;
7285 int32_t src_top=0;
7286 int32_t src_bottom=0;
7287 int32_t src_left=0, src_right=0;
7288 int32_t src_width=0, src_height=0;
7289 int32_t dest_left=0, dest_right=0;
7290 int32_t dest_width=0, dest_height=0;
7291 int32_t rows=0, cols=0;
7292
7293 if(rect)
7294 {
7295 dest_top=TILEROW(dest_first);
7296 dest_bottom=TILEROW(dest_last);
7297 src_top=TILEROW(src_first);
7298 src_bottom=TILEROW(src_last);
7299
7300 src_left= zc_min(TILECOL(src_first),TILECOL(src_last));
7301 src_right=zc_max(TILECOL(src_first),TILECOL(src_last));
7302 src_first=(src_top * TILES_PER_ROW)+src_left;
7303 src_last= (src_bottom*TILES_PER_ROW)+src_right;
7304
7305 dest_left= zc_min(TILECOL(dest_first),TILECOL(dest_last));
7306 dest_right=zc_max(TILECOL(dest_first),TILECOL(dest_last));
7307 dest_first=(dest_top * TILES_PER_ROW)+dest_left;
7308 dest_last= (dest_bottom*TILES_PER_ROW)+dest_right;
7309
7310 //if no dest range set, then set one
7311 if((dest_first==dest_last)&&(src_first!=src_last))
7312 {
7313 if(alt)
7314 {
7315 dest_left=dest_right-(src_right-src_left);
7316 }
7317 else
7318 {
7319 dest_right=dest_left+(src_right-src_left);
7320 }
7321
7322 if(shift)
7323 {
7324 dest_top=dest_bottom-(src_bottom-src_top);
7325 }
7326 else
7327 {
7328 dest_bottom=dest_top+(src_bottom-src_top);
7329 }
7330
7331 dest_first=(dest_top * TILES_PER_ROW)+dest_left;
7332 dest_last= (dest_bottom*TILES_PER_ROW)+dest_right;
7333 }
7334 else
7335 {
7336 if(dest_right-dest_left<src_right-src_left) //destination is shorter than source
7337 {
7338 if(alt) //copy from right tile instead of left
7339 {
7340 src_left=src_right-(dest_right-dest_left);
7341 }
7342 else //copy from left tile
7343 {
7344 src_right=src_left+(dest_right-dest_left);
7345 }
7346 }
7347 else if(dest_right-dest_left>src_right-src_left) //destination is longer than source
7348 {
7349 if(alt) //copy from right tile instead of left
7350 {
7351 dest_left=dest_right-(src_right-src_left);
7352 }
7353 else //copy from left tile
7354 {
7355 dest_right=dest_left+(src_right-src_left);
7356 }
7357 }
7358
7359 if(dest_bottom-dest_top<src_bottom-src_top) //destination is shorter than source
7360 {
7361 if(shift) //copy from bottom tile instead of top
7362 {
7363 src_top=src_bottom-(dest_bottom-dest_top);
7364 }
7365 else //copy from top tile
7366 {
7367 src_bottom=src_top+(dest_bottom-dest_top);
7368 }
7369 }
7370 else if(dest_bottom-dest_top>src_bottom-src_top) //destination is longer than source
7371 {
7372 if(shift) //copy from bottom tile instead of top
7373 {
7374 dest_top=dest_bottom-(src_bottom-src_top);
7375 }
7376 else //copy from top tile
7377 {
7378 dest_bottom=dest_top+(src_bottom-src_top);
7379 }
7380 }
7381
7382 src_first=(src_top * TILES_PER_ROW)+src_left;
7383 src_last= (src_bottom*TILES_PER_ROW)+src_right;
7384 dest_first=(dest_top * TILES_PER_ROW)+dest_left;
7385 dest_last= (dest_bottom*TILES_PER_ROW)+dest_right;
7386 }
7387
7388 cols=src_right-src_left+1;
7389 rows=src_bottom-src_top+1;
7390
7391 dest_width=dest_right-dest_left+1;
7392 dest_height=dest_bottom-dest_top+1;
7393 src_width=src_right-src_left+1;
7394 src_height=src_bottom-src_top+1;
7395
7396 }
7397 else //!rect
7398 {
7399 //if no dest range set, then set one
7400 if((dest_first==dest_last)&&(src_first!=src_last))
7401 {
7402 if(alt)
7403 {
7404 dest_first=dest_last-(src_last-src_first);
7405 }
7406 else
7407 {
7408 dest_last=dest_first+(src_last-src_first);
7409 }
7410 }
7411 else
7412 {
7413 if(dest_last-dest_first<src_last-src_first) //destination is shorter than source
7414 {
7415 if(alt) //copy from last tile instead of first
7416 {
7417 src_first=src_last-(dest_last-dest_first);
7418 }
7419 else //copy from first tile
7420 {
7421 src_last=src_first+(dest_last-dest_first);
7422 }
7423 }
7424 else if(dest_last-dest_first>src_last-src_first) //destination is longer than source
7425 {
7426 if(alt) //copy from last tile instead of first
7427 {
7428 dest_first=dest_last-(src_last-src_first);
7429 }
7430 else //copy from first tile
7431 {
7432 dest_last=dest_first+(src_last-src_first);
7433 }
7434 }
7435 }
7436
7437 copies=dest_last-dest_first+1;
7438 }
7439
7440
7441
7442 char buf2[80], buf3[80], buf4[80];
7443 sprintf(buf2, " ");
7444 sprintf(buf3, " ");
7445 sprintf(buf4, " ");
7446
7447 // warn if range extends beyond last tile
7448 sprintf(buf4, "Some tiles will not be %s", move?"moved.":"copied.");
7449
7450 if(dest_last>=NEWMAXTILES)
7451 {
7452 sprintf(buf4, "%s operation cancelled.", move?"Move":"Copy");
7453 jwin_alert("Destination Error", "The destination extends beyond", "the last available tile row.", buf4, "&OK", NULL, 'o', 0, get_zc_font(font_lfont));
7454 return false;
7455 //fix this below to allow the operation to complete with a modified start or end instead of just cancelling
7456 //if (jwin_alert("Destination Error", "The destination extends beyond", "the last available tile row.", buf4, "&OK", "&Cancel", 'o', 'c', get_zc_font(font_lfont))==2)
7457 // {
7458 // return false;
7459 // }
7460 }
7461
7462
7463 TileMoveUndo on_undo;
7464 // Overwrite warnings
7465 TileMoveProcess dest{rect, dest_left, dest_top, dest_width, dest_height, dest_first, dest_last};
7466 if(move)
7467 {
7468 TileMoveProcess src{rect, src_left, src_top, src_width, src_height, src_first, src_last};
7469 if(!handle_tile_move(dest, src, dest_first-src_first, on_undo))
7470 return false;
7471 }
7472 else
7473 {
7474 if(!handle_tile_move(dest))
7475 return false;
7476 }
7477 // copy tiles and delete if needed (move)
7478
7479 {
7480 go_tiles();
7481
7482 int32_t diff=dest_first-src_first;
7483
7484 if(rect)
7485 {
7486 for(int32_t r=0; r<rows; ++r)
7487 {
7488 for(int32_t c=0; c<cols; ++c)
7489 {
7490 int32_t dt=(dest_first+((r*TILES_PER_ROW)+c));
7491 int32_t st=(src_first+((r*TILES_PER_ROW)+c));
7492
7493 if(dt>=NEWMAXTILES)
7494 continue;
7495
7496 overlay_tile(newtilebuf,dt,st,cs,backwards);
7497
7498 }
7499 }
7500 }
7501 else
7502 {
7503 for(int32_t c=0; c<copies; ++c)
7504 {
7505 int32_t dt=(dest_first+c);
7506 int32_t st=(src_first+c);
7507
7508 if(dt>=NEWMAXTILES)
7509 continue;
7510
7511 overlay_tile(newtilebuf,dt,st,cs,backwards);
7512
7513 if(move)
7514 {
7515 if(st<dest_first||st>(dest_first+c-1))
7516 reset_tile(newtilebuf, st, tf4Bit);
7517 }
7518 }
7519 }
7520 }
7521
7522 //now that tiles have moved, fix these buffers -DD
7523 register_blank_tiles();
7524 register_used_tiles();
7525
7526 if(move)
7527 last_tile_move_list = std::move(on_undo);
7528 return true;
7529 }
7530 //
7531 bool do_movetile_united(tile_move_data const& tmd)
7532 {
7533 char buf2[80], buf3[80], buf4[80];
7534 sprintf(buf2, " ");
7535 sprintf(buf3, " ");
7536 sprintf(buf4, " ");
7537
7538 // warn if range extends beyond last tile
7539 sprintf(buf4, "Some tiles will not be %s", tmd.move?"moved.":"copied.");
7540
7541 if(tmd.dest_last>=NEWMAXTILES)
7542 {
7543 sprintf(buf4, "%s operation cancelled.", tmd.move?"Move":"Copy");
7544 jwin_alert("Destination Error", "The destination extends beyond", "the last available tile row.", buf4, "&OK", NULL, 'o', 0, get_zc_font(font_lfont));
7545 return false;
7546 }
7547
7548 TileMoveUndo on_undo;
7549 // Overwrite warnings
7550 TileMoveProcess dest{tmd.rect, tmd.dest_left, tmd.dest_top, tmd.dest_width, tmd.dest_height, tmd.dest_first, tmd.dest_last};
7551 if(tmd.move)
7552 {
7553 TileMoveProcess src{tmd.rect, tmd.src_left, tmd.src_top, tmd.src_width, tmd.src_height, tmd.src_first, tmd.src_last};
7554 if(!handle_tile_move(dest, src, tmd.dest_first-tmd.src_first, on_undo))
7555 return false;
7556 }
7557 else
7558 {
7559 if(!handle_tile_move(dest))
7560 return false;
7561 }
7562
7563 // copy tiles and delete if needed (tmd.move)
7564 {
7565 go_tiles();
7566
7567 if(tmd.rect)
7568 {
7569 for(int32_t r=0; r<tmd.rows; ++r)
7570 {
7571 for(int32_t c=0; c<tmd.cols; ++c)
7572 {
7573 int32_t dt=(tmd.dest_first+((r*TILES_PER_ROW)+c));
7574 int32_t st=(tmd.src_first+((r*TILES_PER_ROW)+c));
7575
7576 if(dt>=NEWMAXTILES)
7577 continue;
7578
7579 reset_tile(newtilebuf, dt, newundotilebuf[st].format);
7580
7581 for(int32_t j=0; j<tilesize(newundotilebuf[st].format); j++)
7582 {
7583 newtilebuf[dt].data[j]=newundotilebuf[st].data[j];
7584 }
7585
7586 if(tmd.move)
7587 {
7588 if((st<tmd.dest_first||st>tmd.dest_first+((tmd.rows-1)*TILES_PER_ROW)+(tmd.cols-1)))
7589 reset_tile(newtilebuf, st, tf4Bit);
7590 else
7591 {
7592 int32_t destLeft=tmd.dest_first%TILES_PER_ROW;
7593 int32_t destRight=(tmd.dest_first+tmd.cols-1)%TILES_PER_ROW;
7594 if(destLeft<=destRight)
7595 {
7596 if(st%TILES_PER_ROW<destLeft || st%TILES_PER_ROW>destRight)
7597 reset_tile(newtilebuf, st, tf4Bit);
7598 }
7599 else // Wrapped around
7600 {
7601 if(st%TILES_PER_ROW<destLeft && st%TILES_PER_ROW>destRight)
7602 reset_tile(newtilebuf, st, tf4Bit);
7603 }
7604 }
7605 }
7606 }
7607 }
7608 }
7609 else
7610 {
7611 for(int32_t c=0; c<tmd.copies; ++c)
7612 {
7613 int32_t dt=(tmd.dest_first+c);
7614 int32_t st=(tmd.src_first+c);
7615
7616 if(dt>=NEWMAXTILES)
7617 continue;
7618
7619 reset_tile(newtilebuf, dt, newundotilebuf[st].format);
7620
7621 for(int32_t j=0; j<tilesize(newundotilebuf[st].format); j++)
7622 {
7623 newtilebuf[dt].data[j]=newundotilebuf[st].data[j];
7624 }
7625
7626 if(tmd.move)
7627 {
7628 if(st<tmd.dest_first||st>(tmd.dest_first+c-1))
7629 reset_tile(newtilebuf, st, tf4Bit);
7630 }
7631 }
7632 }
7633 }
7634
7635 //now that tiles have moved, fix these buffers -DD
7636 register_blank_tiles();
7637 register_used_tiles();
7638
7639 if(tmd.move)
7640 last_tile_move_list = std::move(on_undo);
7641 return true;
7642 }
7643
7644 bool copy_tiles_united(int32_t &tile,int32_t &tile2,int32_t &copy,int32_t &copycnt, bool rect, bool move)
7645 {
7646 bool alt=(key[KEY_ALT]||key[KEY_ALTGR]);
7647 bool shift=(key[KEY_LSHIFT] || key[KEY_RSHIFT]);
7648
7649 // if tile>tile2 then swap them
7650 if(tile>tile2)
7651 {
7652 zc_swap(tile, tile2);
7653 }
7654
7655 // alt=copy from right
7656 // shift=copy from bottom
7657 tile_move_data tmd;
7658
7659 tmd.copies=copycnt;
7660 tmd.dest_first=tile;
7661 tmd.dest_last=tile2;
7662 tmd.src_first=copy;
7663 tmd.src_last=copy+tmd.copies-1;
7664 tmd.rect = rect;
7665 tmd.move = move;
7666
7667 if(rect)
7668 {
7669 tmd.dest_top=TILEROW(tmd.dest_first);
7670 tmd.dest_bottom=TILEROW(tmd.dest_last);
7671 tmd.src_top=TILEROW(tmd.src_first);
7672 tmd.src_bottom=TILEROW(tmd.src_last);
7673
7674 tmd.src_left= zc_min(TILECOL(tmd.src_first),TILECOL(tmd.src_last));
7675 tmd.src_right=zc_max(TILECOL(tmd.src_first),TILECOL(tmd.src_last));
7676 tmd.src_first=(tmd.src_top * TILES_PER_ROW)+tmd.src_left;
7677 tmd.src_last= (tmd.src_bottom*TILES_PER_ROW)+tmd.src_right;
7678
7679 tmd.dest_left= zc_min(TILECOL(tmd.dest_first),TILECOL(tmd.dest_last));
7680 tmd.dest_right=zc_max(TILECOL(tmd.dest_first),TILECOL(tmd.dest_last));
7681 tmd.dest_first=(tmd.dest_top * TILES_PER_ROW)+tmd.dest_left;
7682 tmd.dest_last= (tmd.dest_bottom*TILES_PER_ROW)+tmd.dest_right;
7683
7684 //if no dest range set, then set one
7685 if((tmd.dest_first==tmd.dest_last)&&(tmd.src_first!=tmd.src_last))
7686 {
7687 if(alt)
7688 {
7689 tmd.dest_left=tmd.dest_right-(tmd.src_right-tmd.src_left);
7690 }
7691 else
7692 {
7693 tmd.dest_right=tmd.dest_left+(tmd.src_right-tmd.src_left);
7694 }
7695
7696 if(shift)
7697 {
7698 tmd.dest_top=tmd.dest_bottom-(tmd.src_bottom-tmd.src_top);
7699 }
7700 else
7701 {
7702 tmd.dest_bottom=tmd.dest_top+(tmd.src_bottom-tmd.src_top);
7703 }
7704
7705 tmd.dest_first=(tmd.dest_top * TILES_PER_ROW)+tmd.dest_left;
7706 tmd.dest_last= (tmd.dest_bottom*TILES_PER_ROW)+tmd.dest_right;
7707 }
7708 else
7709 {
7710 if(tmd.dest_right-tmd.dest_left<tmd.src_right-tmd.src_left) //destination is shorter than source
7711 {
7712 if(alt) //copy from right tile instead of left
7713 {
7714 tmd.src_left=tmd.src_right-(tmd.dest_right-tmd.dest_left);
7715 }
7716 else //copy from left tile
7717 {
7718 tmd.src_right=tmd.src_left+(tmd.dest_right-tmd.dest_left);
7719 }
7720 }
7721 else if(tmd.dest_right-tmd.dest_left>tmd.src_right-tmd.src_left) //destination is longer than source
7722 {
7723 if(alt) //copy from right tile instead of left
7724 {
7725 tmd.dest_left=tmd.dest_right-(tmd.src_right-tmd.src_left);
7726 }
7727 else //copy from left tile
7728 {
7729 tmd.dest_right=tmd.dest_left+(tmd.src_right-tmd.src_left);
7730 }
7731 }
7732
7733 if(tmd.dest_bottom-tmd.dest_top<tmd.src_bottom-tmd.src_top) //destination is shorter than source
7734 {
7735 if(shift) //copy from bottom tile instead of top
7736 {
7737 tmd.src_top=tmd.src_bottom-(tmd.dest_bottom-tmd.dest_top);
7738 }
7739 else //copy from top tile
7740 {
7741 tmd.src_bottom=tmd.src_top+(tmd.dest_bottom-tmd.dest_top);
7742 }
7743 }
7744 else if(tmd.dest_bottom-tmd.dest_top>tmd.src_bottom-tmd.src_top) //destination is longer than source
7745 {
7746 if(shift) //copy from bottom tile instead of top
7747 {
7748 tmd.dest_top=tmd.dest_bottom-(tmd.src_bottom-tmd.src_top);
7749 }
7750 else //copy from top tile
7751 {
7752 tmd.dest_bottom=tmd.dest_top+(tmd.src_bottom-tmd.src_top);
7753 }
7754 }
7755
7756 tmd.src_first=(tmd.src_top * TILES_PER_ROW)+tmd.src_left;
7757 tmd.src_last= (tmd.src_bottom*TILES_PER_ROW)+tmd.src_right;
7758 tmd.dest_first=(tmd.dest_top * TILES_PER_ROW)+tmd.dest_left;
7759 tmd.dest_last= (tmd.dest_bottom*TILES_PER_ROW)+tmd.dest_right;
7760 }
7761
7762 tmd.cols=tmd.src_right-tmd.src_left+1;
7763 tmd.rows=tmd.src_bottom-tmd.src_top+1;
7764
7765 tmd.dest_width=tmd.dest_right-tmd.dest_left+1;
7766 tmd.dest_height=tmd.dest_bottom-tmd.dest_top+1;
7767 tmd.src_width=tmd.src_right-tmd.src_left+1;
7768 tmd.src_height=tmd.src_bottom-tmd.src_top+1;
7769
7770 }
7771 else //!rect
7772 {
7773 //if no dest range set, then set one
7774 if((tmd.dest_first==tmd.dest_last)&&(tmd.src_first!=tmd.src_last))
7775 {
7776 if(alt)
7777 {
7778 tmd.dest_first=tmd.dest_last-(tmd.src_last-tmd.src_first);
7779 }
7780 else
7781 {
7782 tmd.dest_last=tmd.dest_first+(tmd.src_last-tmd.src_first);
7783 }
7784 }
7785 else
7786 {
7787 if(tmd.dest_last-tmd.dest_first<tmd.src_last-tmd.src_first) //destination is shorter than source
7788 {
7789 if(alt) //copy from last tile instead of first
7790 {
7791 tmd.src_first=tmd.src_last-(tmd.dest_last-tmd.dest_first);
7792 }
7793 else //copy from first tile
7794 {
7795 tmd.src_last=tmd.src_first+(tmd.dest_last-tmd.dest_first);
7796 }
7797 }
7798 else if(tmd.dest_last-tmd.dest_first>tmd.src_last-tmd.src_first) //destination is longer than source
7799 {
7800 if(alt) //copy from last tile instead of first
7801 {
7802 tmd.dest_first=tmd.dest_last-(tmd.src_last-tmd.src_first);
7803 }
7804 else //copy from first tile
7805 {
7806 tmd.dest_last=tmd.dest_first+(tmd.src_last-tmd.src_first);
7807 }
7808 }
7809 }
7810
7811 tmd.copies=tmd.dest_last-tmd.dest_first+1;
7812 }
7813
7814 return do_movetile_united(tmd);
7815 }
7816
7817 //
7818
7819 bool copy_tiles_united_floodfill(int32_t &tile,int32_t &tile2,int32_t &copy,int32_t &copycnt, bool rect, bool move)
7820 {
7821 assert(!move); //not implemented
7822
7823 // if tile>tile2 then swap them
7824 if(tile>tile2)
7825 {
7826 zc_swap(tile, tile2);
7827 }
7828
7829 tile_move_data tmd;
7830 tmd.copies=copycnt;
7831 tmd.dest_first=tile;
7832 tmd.dest_last=tile2;
7833 tmd.src_first=copy;
7834 tmd.src_last=copy+tmd.copies-1;
7835
7836
7837
7838 if(rect)
7839 {
7840 tmd.dest_top=TILEROW(tmd.dest_first);
7841 tmd.dest_bottom=TILEROW(tmd.dest_last);
7842 //tmd.src_top=TILEROW(tmd.src_first);
7843 //tmd.src_bottom=TILEROW(tmd.src_last);
7844
7845 //tmd.src_left= zc_min(TILECOL(tmd.src_first),TILECOL(tmd.src_last));
7846 //tmd.src_right=zc_max(TILECOL(tmd.src_first),TILECOL(tmd.src_last));
7847 //tmd.src_first=(tmd.src_top * TILES_PER_ROW)+tmd.src_left;
7848 //tmd.src_last= (tmd.src_bottom*TILES_PER_ROW)+tmd.src_right;
7849
7850 tmd.dest_left= zc_min(TILECOL(tmd.dest_first),TILECOL(tmd.dest_last));
7851 tmd.dest_right=zc_max(TILECOL(tmd.dest_first),TILECOL(tmd.dest_last));
7852 tmd.dest_first=(tmd.dest_top * TILES_PER_ROW)+tmd.dest_left;
7853 tmd.dest_last= (tmd.dest_bottom*TILES_PER_ROW)+tmd.dest_right;
7854
7855
7856
7857
7858 tmd.dest_width=tmd.dest_right-tmd.dest_left;
7859 tmd.dest_height=tmd.dest_bottom-tmd.dest_top;
7860
7861 tmd.cols=tmd.dest_width+1;
7862 tmd.rows=tmd.dest_height+1;
7863
7864 al_trace("tmd.rows: %d\n", tmd.rows);
7865 al_trace("tmd.cols: %d\n", tmd.cols);
7866
7867
7868 }
7869 else //!rect
7870 {
7871 tmd.copies=tmd.dest_last-tmd.dest_first+1;
7872 }
7873
7874
7875
7876 char buf2[80], buf3[80], buf4[80];
7877 sprintf(buf2, " ");
7878 sprintf(buf3, " ");
7879 sprintf(buf4, " ");
7880
7881 // warn if range extends beyond last tile
7882 sprintf(buf4, "Some tiles will not be %s", move?"moved.":"copied.");
7883
7884 if(tmd.dest_last>=NEWMAXTILES)
7885 {
7886 sprintf(buf4, "%s operation cancelled.", move?"Move":"Copy");
7887 jwin_alert("Destination Error", "The destination extends beyond", "the last available tile row.", buf4, "&OK", NULL, 'o', 0, get_zc_font(font_lfont));
7888 return false;
7889 //fix this below to allow the operation to complete with a modified start or end instead of just cancelling
7890 //if (jwin_alert("Destination Error", "The destination extends beyond", "the last available tile row.", buf4, "&OK", "&Cancel", 'o', 'c', get_zc_font(font_lfont))==2)
7891 // {
7892 // return false;
7893 // }
7894 }
7895
7896 TileMoveUndo on_undo;
7897 // Overwrite warnings
7898 TileMoveProcess dest{tmd.rect, tmd.dest_left, tmd.dest_top, tmd.dest_width, tmd.dest_height, tmd.dest_first, tmd.dest_last};
7899 if(tmd.move)
7900 {
7901 TileMoveProcess src{tmd.rect, tmd.src_left, tmd.src_top, tmd.src_width, tmd.src_height, tmd.src_first, tmd.src_last};
7902 if(!handle_tile_move(dest, src, tmd.dest_first-tmd.src_first, on_undo))
7903 return false;
7904 }
7905 else
7906 {
7907 if(!handle_tile_move(dest))
7908 return false;
7909 }
7910
7911 // copy tiles and delete if needed (move)
7912
7913 {
7914 go_tiles();
7915
7916 int32_t diff=tmd.dest_first-tmd.src_first;
7917
7918 if(rect)
7919 {
7920 al_trace("floodfill, rect\n");
7921 al_trace("tmd.rows: %d\n", tmd.rows);
7922 al_trace("tmd.cols: %d\n", tmd.cols);
7923 for(int32_t r=0; r<tmd.rows; ++r)
7924 {
7925 for(int32_t c=0; c<tmd.cols; ++c)
7926 {
7927 int32_t dt=(tmd.dest_first+((r*TILES_PER_ROW)+c));
7928 //int32_t st=(tmd.src_first+((r*TILES_PER_ROW)+c));
7929
7930 if(dt>=NEWMAXTILES)
7931 continue;
7932
7933 reset_tile(newtilebuf, dt, newundotilebuf[copy].format);
7934
7935 for(int32_t j=0; j<tilesize(newundotilebuf[copy].format); j++)
7936 {
7937 newtilebuf[dt].data[j]=newundotilebuf[copy].data[j];
7938 }
7939 }
7940 }
7941 }
7942 else
7943 {
7944 for(int32_t c=0; c<tmd.copies; ++c)
7945 {
7946 int32_t dt=(tmd.dest_first+c);
7947 int32_t st=(tmd.src_first+c);
7948
7949 if(dt>=NEWMAXTILES)
7950 continue;
7951
7952 reset_tile(newtilebuf, dt, newundotilebuf[copy].format);
7953
7954 for(int32_t j=0; j<tilesize(newundotilebuf[copy].format); j++)
7955 {
7956 newtilebuf[dt].data[j]=newundotilebuf[copy].data[j];
7957 }
7958
7959 }
7960 }
7961 }
7962
7963 //now that tiles have moved, fix these buffers -DD
7964 register_blank_tiles();
7965 register_used_tiles();
7966
7967 if(tmd.move)
7968 last_tile_move_list = std::move(on_undo);
7969 return true;
7970 }
7971 //
7972
7973 bool copy_tiles_floodfill(int32_t &tile,int32_t &tile2,int32_t &copy,int32_t &copycnt, bool rect_sel, bool move)
7974 {
7975 al_trace("Floodfill Psste\n");
7976 bool ctrl=(CHECK_CTRL_CMD);
7977 bool copied=false;
7978 copied=copy_tiles_united_floodfill(tile,tile2,copy,copycnt,rect_sel,move);
7979
7980 if(copied)
7981 {
7982 if(!ctrl)
7983 {
7984 copy=-1;
7985 tile2=tile;
7986 }
7987
7988 mark_save_dirty();
7989 }
7990
7991 return copied;
7992 }
7993
7994 bool copy_tiles(int32_t &tile,int32_t &tile2,int32_t &copy,int32_t &copycnt, bool rect_sel, bool move)
7995 {
7996 bool ctrl=(CHECK_CTRL_CMD);
7997 bool copied=false;
7998 copied=copy_tiles_united(tile,tile2,copy,copycnt,rect_sel,move);
7999
8000 if(copied)
8001 {
8002 if(!ctrl)
8003 {
8004 copy=-1;
8005 tile2=tile;
8006 }
8007
8008 mark_save_dirty();
8009 }
8010
8011 return copied;
8012 }
8013
8014 bool scale_or_rotate_tiles(int32_t &tile, int32_t &tile2, int32_t &cs, bool rotate)
8015 {
8016 // if tile>tile2 then swap them
8017 if(tile>tile2)
8018 {
8019 zc_swap(tile, tile2);
8020 }
8021 int32_t src_top = TILEROW(tile);
8022 int32_t src_bottom = TILEROW(tile2);
8023 int32_t src_left = zc_min(TILECOL(tile),TILECOL(tile2));
8024 int32_t src_right = zc_max(TILECOL(tile),TILECOL(tile2));
8025 int32_t src_first = (src_top * TILES_PER_ROW)+src_left;
8026 int32_t src_last = (src_bottom*TILES_PER_ROW)+src_right;
8027
8028 int32_t src_width = src_right-src_left+1,
8029 src_height = src_bottom-src_top+1;
8030 int32_t dest_width = src_width, dest_height = src_height;
8031 zfix dest_rot = 0_zf;
8032 if(rotate)
8033 RotateTileDialog(&dest_width, &dest_height, &dest_rot).show();
8034 else
8035 ScaleTileDialog(&dest_width, &dest_height).show();
8036 if (rotate)
8037 {
8038 if (dest_rot == 0) return false;
8039 }
8040 else
8041 {
8042 if (dest_width == src_width && dest_height == src_height) return false; //no scaling
8043 }
8044 dest_width = vbound(dest_width, 1, 20);
8045 dest_height = vbound(dest_height, 1, 20);
8046
8047 int32_t dest_top = src_top;
8048 int32_t dest_bottom = src_top+dest_height-1;
8049 int32_t dest_left = src_left;
8050 int32_t dest_right = src_left+dest_width-1;
8051 int32_t dest_first = src_first;
8052 int32_t dest_last = (dest_bottom*TILES_PER_ROW)+dest_right;
8053
8054
8055 if(dest_last>=NEWMAXTILES)
8056 {
8057 InfoDialog("Destination Error", "The destination extends beyond the last available tile row. Scale operation cancelled.").show();
8058 return false;
8059 }
8060
8061 // Overwrite warnings
8062 if(!handle_tile_move({true, dest_left, dest_top, dest_width, dest_height, dest_first, dest_last}))
8063 return false;
8064
8065 //Do the rotate
8066 {
8067 go_tiles();
8068
8069 int32_t diff=dest_first-src_first;
8070 BITMAP *srcbmp = create_bitmap_ex(8,src_width*16,src_height*16),
8071 *destbmp = create_bitmap_ex(8,dest_width*16,dest_height*16);
8072 clear_bitmap(srcbmp); clear_bitmap(destbmp);
8073 overtileblock16(srcbmp, src_first, 0, 0, src_width, src_height, cs, 0);
8074 bool is8bit = newtilebuf[src_first].format == tf8Bit;
8075 if (rotate)
8076 {
8077 rotate_sprite(destbmp, srcbmp, 0, 0, ftofix(dest_rot * 0.7111111111111));
8078 }
8079 else
8080 {
8081 stretch_blit(srcbmp, destbmp, 0, 0, srcbmp->w, srcbmp->h,
8082 0, 0, destbmp->w, destbmp->h);
8083 }
8084 int32_t mhei = zc_max(src_height,dest_height),
8085 mwid = zc_max(src_width, dest_width);
8086 for(int32_t r=0; r<mhei; ++r)
8087 {
8088 for(int32_t c=0; c<mwid; ++c)
8089 {
8090 int32_t dt=(dest_first+((r*TILES_PER_ROW)+c));
8091
8092 if(dt>=NEWMAXTILES)
8093 continue;
8094 if(r < dest_height && c < dest_width)
8095 {
8096 write_tile(newtilebuf, destbmp, dt, c*16, r*16, is8bit, false);
8097 }
8098 else reset_tile(newtilebuf, dt, tf4Bit);
8099 }
8100 }
8101 }
8102
8103 register_blank_tiles();
8104 register_used_tiles();
8105 return true;
8106 }
8107
8108 void copy_combos(int32_t &tile,int32_t &tile2,int32_t &copy,int32_t &copycnt, bool masscopy)
8109 {
8110 //these 2 shouldn't be needed, but just to be safe...
8111 reset_combo_animations();
8112 reset_combo_animations2();
8113
8114 if(tile2<tile)
8115 {
8116 zc_swap(tile,tile2);
8117 }
8118
8119 auto first = tile;
8120 auto last = masscopy ? tile2 : first + copycnt-1;
8121 if(!handle_combo_move({first,last}))
8122 return;
8123
8124 if(!masscopy)
8125 {
8126 if(tile==copy)
8127 {
8128 copy=-1;
8129 tile2=tile;
8130 return;
8131 }
8132
8133 // go_combos(); // commented because caller does it for us
8134 //if copying to an earlier combo, copy from left to right
8135 //otherwise, copy from right to left
8136 for(int32_t t=(tile<copy)?0:(copycnt-1); (tile<copy)?(t<copycnt):(t>=0); (tile<copy)?(t++):(t--))
8137 {
8138 if(tile+t < MAXCOMBOS)
8139 {
8140 combobuf[tile+t]=combobuf[copy+t];
8141 }
8142 }
8143
8144 copy=-1;
8145 tile2=tile;
8146 mark_save_dirty();
8147 }
8148 else
8149 {
8150 // go_combos();
8151 int32_t src=copy, dest=tile;
8152
8153 do
8154 {
8155 combobuf[dest]=combobuf[src];
8156 ++src;
8157 ++dest;
8158
8159 if((src-copy)==copycnt) src=copy;
8160 }
8161 while(dest<=tile2);
8162
8163 copy=-1;
8164 tile2=tile;
8165 mark_save_dirty();
8166 }
8167
8168 setup_combo_animations();
8169 setup_combo_animations2();
8170 }
8171
8172 bool do_movecombo(combo_move_data const& cmd, ComboMoveUndo& on_undo, bool is_undoing)
8173 {
8174 reset_combo_animations();
8175 reset_combo_animations2();
8176 go_combos();
8177
8178 auto diff = cmd.tile - cmd.copy1;
8179 if(is_undoing)
8180 on_undo.undo();
8181 else if(!handle_combo_move({cmd.tile,cmd.tile+cmd.copycnt-1},{cmd.copy1,cmd.copy1+cmd.copycnt-1}, diff, on_undo))
8182 return false;
8183
8184 for(int32_t t=(cmd.tile<cmd.copy1)?0:(cmd.copycnt-1); (cmd.tile<cmd.copy1)?(t<cmd.copycnt):(t>=0); (cmd.tile<cmd.copy1)?(t++):(t--))
8185 {
8186 if(cmd.tile+t < MAXCOMBOS)
8187 {
8188 combobuf[cmd.tile+t]=combobuf[cmd.copy1+t];
8189 clear_combo(cmd.copy1+t);
8190 }
8191 }
8192
8193 setup_combo_animations();
8194 setup_combo_animations2();
8195 mark_save_dirty();
8196 return true;
8197 }
8198
8199 void move_combos(int32_t &tile,int32_t &tile2,int32_t &copy,int32_t &copycnt)
8200 {
8201 if(tile2<tile)
8202 {
8203 zc_swap(tile,tile2);
8204 }
8205
8206 if(tile==copy)
8207 {
8208 copy=-1;
8209 tile2=tile;
8210 return;
8211 }
8212
8213 combo_move_data cmd;
8214 cmd.tile = tile;
8215 cmd.tile2 = tile2;
8216 cmd.copy1 = copy;
8217 cmd.copycnt = copycnt;
8218
8219 ComboMoveUndo on_undo;
8220 if(!do_movecombo(cmd, on_undo))
8221 return;
8222 last_combo_move_list = std::move(on_undo);
8223 copy=-1;
8224 tile2=tile;
8225 }
8226
8227 void do_delete_tiles(int32_t firsttile, int32_t lasttile, bool rect_sel)
8228 {
8229 if(firsttile > lasttile)
8230 zc_swap(firsttile,lasttile);
8231 int32_t coldiff = 0;
8232 if(rect_sel && TILECOL(firsttile)>TILECOL(lasttile))
8233 {
8234 coldiff=TILECOL(firsttile)-TILECOL(lasttile);
8235 firsttile-=coldiff;
8236 lasttile+=coldiff;
8237 }
8238 for(int32_t t=firsttile; t<=lasttile; ++t)
8239 if(!rect_sel ||
8240 ((TILECOL(t)>=TILECOL(firsttile)) &&
8241 (TILECOL(t)<=TILECOL(lasttile))))
8242 reset_tile(newtilebuf, t, tf4Bit);
8243 mark_save_dirty();
8244 register_blank_tiles();
8245 }
8246
8247 void delete_tiles(int32_t &tile,int32_t &tile2,bool rect_sel)
8248 {
8249 char buf[40];
8250
8251 if(tile==tile2)
8252 {
8253 sprintf(buf,"Delete tile %d?",tile);
8254 }
8255 else
8256 {
8257 sprintf(buf,"Delete tiles %d-%d?",zc_min(tile,tile2),zc_max(tile,tile2));
8258 }
8259
8260 if(jwin_alert("Confirm Delete",buf,NULL,NULL,"&Yes","&No",'y','n',get_zc_font(font_lfont))==1)
8261 {
8262 int32_t firsttile=zc_min(tile,tile2), lasttile=zc_max(tile,tile2), coldiff=0;
8263
8264 go_tiles();
8265
8266 //if copying to an earlier tile, copy from left to right
8267 //otherwise, copy from right to left
8268 do_delete_tiles(firsttile, lasttile, rect_sel);
8269
8270 tile=tile2=zc_min(tile,tile2);
8271 mark_save_dirty();
8272 register_blank_tiles();
8273 }
8274 }
8275
8276 void overlay_tile2(int32_t dest,int32_t src,int32_t cs,bool backwards)
8277 {
8278 byte buf[256];
8279 go_tiles();
8280
8281 unpack_tile(newtilebuf, dest, 0, false);
8282
8283 for(int32_t i=0; i<256; i++)
8284 buf[i] = unpackbuf[i];
8285
8286 unpack_tile(newtilebuf, src, 0, false);
8287
8288 if(newtilebuf[src].format>tf4Bit)
8289 {
8290 cs=0;
8291 }
8292
8293 cs &= 15;
8294 cs <<= CSET_SHFT;
8295
8296 for(int32_t i=0; i<256; i++)
8297 {
8298 if(backwards)
8299 {
8300 if(!buf[i])
8301 {
8302 buf[i] = unpackbuf[i]+cs;
8303 }
8304 }
8305 else
8306 {
8307 if(unpackbuf[i])
8308 {
8309 buf[i] = unpackbuf[i]+cs;
8310 }
8311 }
8312 }
8313
8314 pack_tile(newtilebuf, buf,dest);
8315 mark_save_dirty();
8316 }
8317
8318 void mass_overlay_tile(int32_t dest1, int32_t dest2, int32_t src, int32_t cs, bool backwards, bool rect_sel)
8319 {
8320 //byte buf[256];
8321 go_tiles();
8322
8323 if(!rect_sel)
8324 {
8325 for(int32_t d=dest1; d <= dest2; ++d)
8326 {
8327 /*unpack_tile(newtilebuf, d, 0, false);
8328
8329 for(int32_t i=0; i<256; i++)
8330 {
8331 if(!backwards)
8332 {
8333 if(!buf[i])
8334 {
8335 buf[i] = unpackbuf[i] + cs;
8336 }
8337 }
8338 else
8339 {
8340 if(unpackbuf[i])
8341 {
8342 buf[i] = unpackbuf[i] + cs;
8343 }
8344 }
8345 }
8346
8347 pack_tile(newtilebuf, buf,d);
8348 */
8349
8350 overlay_tile(newtilebuf,d,src,cs,backwards);
8351
8352 if(!blank_tile_table[src])
8353 {
8354 blank_tile_table[d]=false;
8355 }
8356 }
8357 }
8358 else
8359 {
8360 int32_t rmin=zc_min(TILEROW(dest1),TILEROW(dest2));
8361 int32_t rmax=zc_max(TILEROW(dest1),TILEROW(dest2));
8362 int32_t cmin=zc_min(TILECOL(dest1),TILECOL(dest2));
8363 int32_t cmax=zc_max(TILECOL(dest1),TILECOL(dest2));
8364 int32_t d=0;
8365
8366 for(int32_t j=cmin; j<=cmax; ++j)
8367 {
8368 for(int32_t k=rmin; k<=rmax; ++k)
8369 {
8370 d=j+TILES_PER_ROW*k;
8371 /*unpack_tile(newtilebuf, d, 0, false);
8372
8373 for(int32_t i=0; i<256; i++)
8374 {
8375 if(!backwards)
8376 {
8377 if(!buf[i])
8378 {
8379 buf[i] = unpackbuf[i] + cs;
8380 }
8381 }
8382 else
8383 {
8384 if(unpackbuf[i])
8385 {
8386 buf[i] = unpackbuf[i] + cs;
8387 }
8388 }
8389 }
8390
8391 pack_tile(newtilebuf, buf,d);
8392 */
8393
8394 overlay_tile(newtilebuf,d,src,cs,backwards);
8395
8396 if(!blank_tile_table[src])
8397 {
8398 blank_tile_table[d]=false;
8399 }
8400 }
8401 }
8402 }
8403
8404 return;
8405 }
8406
8407 void sel_tile(int32_t &tile, int32_t &tile2, int32_t &first, int32_t type, int32_t s)
8408 {
8409 tile+=s;
8410 bound(tile,0,NEWMAXTILES-1);
8411
8412 if(type!=0 || !(key[KEY_LSHIFT] || key[KEY_RSHIFT]))
8413 tile2 = tile;
8414
8415 first = tile - (tile%TILES_PER_PAGE);
8416 }
8417
8418 void convert_tile(int32_t t, int32_t bp2, int32_t cs, bool shift, bool alt)
8419 {
8420 int32_t cst;
8421
8422 switch(bp2)
8423 {
8424 case tf4Bit:
8425 switch(newtilebuf[t].format)
8426 {
8427 case tf4Bit:
8428 //already in the right format
8429 break;
8430
8431 case tf8Bit:
8432 unpack_tile(newtilebuf, t, 0, true);
8433
8434 if(alt) //reduce
8435 {
8436 for(int32_t i=0; i<256; i++)
8437 {
8438 if(!shift||unpackbuf[i]!=0)
8439 {
8440 unpackbuf[i]=(cset_reduce_table[unpackbuf[i]]);
8441 }
8442 }
8443 }
8444 else //truncate
8445 {
8446 for(int32_t i=0; i<256; i++)
8447 {
8448 unpackbuf[i]&=15;
8449 }
8450 }
8451
8452 reset_tile(newtilebuf, t, tf4Bit);
8453 pack_tile(newtilebuf, unpackbuf, t);
8454 break;
8455 }
8456
8457 break;
8458
8459 case tf8Bit:
8460 switch(newtilebuf[t].format)
8461 {
8462 case tf4Bit:
8463 unpack_tile(newtilebuf, t, 0, true);
8464 cst = cs&15;
8465 cst <<= CSET_SHFT;
8466
8467 for(int32_t i=0; i<256; i++)
8468 {
8469 if(!shift||unpackbuf[i]!=0)
8470 {
8471 unpackbuf[i]+=cst;
8472 }
8473 }
8474
8475 reset_tile(newtilebuf, t, tf8Bit);
8476 pack_tile(newtilebuf, unpackbuf, t);
8477 break;
8478
8479 case tf8Bit:
8480 //already in the right format
8481 break;
8482 }
8483
8484 break;
8485 }
8486 }
8487
8488 static DIALOG create_relational_tiles_dlg[] =
8489 {
8490 // (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp)
8491 12 { jwin_win_proc, 0, 0, 160, 92, vc(0), vc(11), 0, D_EXIT, 0, 0, (void *) "Tile Setup", NULL, NULL },
8492 12 { jwin_rtext_proc, 74, 28, 48, 8, jwin_pal[jcBOXFG], jwin_pal[jcBOX], 0, 0, 0, 0, (void *) "Frames:", NULL, NULL },
8493 12 { jwin_edit_proc, 78, 24, 48, 16, 0, 0, 0, 0, 6, 0, NULL, NULL, NULL },
8494 12 { jwin_radio_proc, 8, 44, 64, 9, vc(14), vc(1), 0, D_SELECTED, 0, 0, (void *) "Relational", NULL, NULL },
8495 12 { jwin_radio_proc, 68, 44, 64, 9, vc(14), vc(1), 0, 0, 0, 0, (void *) "Dungeon Carving", NULL, NULL },
8496 12 { jwin_button_proc, 10, 66, 61, 21, vc(0), vc(11), 13, D_EXIT, 0, 0, (void *) "OK", NULL, NULL },
8497 12 { jwin_button_proc, 90, 66, 61, 21, vc(0), vc(11), 27, D_EXIT, 0, 0, (void *) "Cancel", NULL, NULL },
8498 12 { d_timer_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
8499 12 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
8500 };
8501
8502 void draw_tile_list_window()
8503 {
8504 int32_t w = 640;
8505 int32_t h = 480;
8506
8507 int32_t window_xofs=(zq_screen_w-w-12)>>1;
8508 int32_t window_yofs=(zq_screen_h-h-25-6)>>1;
8509 jwin_draw_win(screen, window_xofs, window_yofs, w+6+6, h+25+6, FR_WIN);
8510 jwin_draw_frame(screen, window_xofs+4, window_yofs+23, w+2+2, h+4+2-64, FR_DEEP);
8511
8512 FONT *oldfont = font;
8513 font = get_zc_font(font_lfont);
8514 jwin_draw_titlebar(screen, window_xofs+3, window_yofs+3, w+6, 18, "Select Tile", true);
8515 font=oldfont;
8516 return;
8517 }
8518
8519 void show_blank_tile(int32_t t)
8520 {
8521 char tbuf[80], tbuf2[80], tbuf3[80];
8522 sprintf(tbuf, "Tile is%s blank.", blank_tile_table[t]?"":" not");
8523 sprintf(tbuf2, "%c %c", blank_tile_quarters_table[t*4]?'X':'-', blank_tile_quarters_table[(t*4)+1]?'X':'-');
8524 sprintf(tbuf3, "%c %c", blank_tile_quarters_table[(t*4)+2]?'X':'-', blank_tile_quarters_table[(t*4)+3]?'X':'-');
8525 jwin_alert("Blank Tile Information",tbuf,tbuf2,tbuf3,"&OK",NULL,13,27,get_zc_font(font_lfont));
8526 }
8527
8528 static void do_convert_tile(int32_t tile, int32_t tile2, int32_t cs, bool rect_sel, int format, bool shift, bool alt, bool skip_prompt = false)
8529 {
8530 int num_bits;
8531 if (format == tf4Bit)
8532 num_bits = 4;
8533 else if (format == tf8Bit)
8534 num_bits = 8;
8535 else assert(false);
8536
8537 char buf[80];
8538 sprintf(buf, "Do you want to convert the selected %s to %d-bit color?", tile==tile2?"tile":"tiles",num_bits);
8539
8540 if (skip_prompt || jwin_alert("Convert Tile?",buf,NULL,NULL,"&Yes","&No",'y','n',get_zc_font(font_lfont))==1)
8541 {
8542 go_tiles();
8543 mark_save_dirty();
8544
8545 if(format == tf4Bit)
8546 {
8547 memset(cset_reduce_table, 0, 256);
8548 memset(col_diff,0,3*128);
8549 calc_cset_reduce_table(RAMpal, cs);
8550 }
8551
8552 int32_t firsttile=zc_min(tile,tile2), lasttile=zc_max(tile,tile2), coldiff=0;
8553
8554 if(rect_sel && TILECOL(firsttile)>TILECOL(lasttile))
8555 {
8556 coldiff=TILECOL(firsttile)-TILECOL(lasttile);
8557 firsttile-=coldiff;
8558 lasttile+=coldiff;
8559 }
8560
8561 for(int32_t t=firsttile; t<=lasttile; t++)
8562 if(!rect_sel ||
8563 ((TILECOL(t)>=TILECOL(firsttile)) &&
8564 (TILECOL(t)<=TILECOL(lasttile))))
8565 convert_tile(t, format, cs, shift, alt);
8566
8567 tile=tile2=zc_min(tile,tile2);
8568 }
8569 }
8570
8571
8572 int32_t readtilefile(PACKFILE *f)
8573 {
8574 dword section_version=0;
8575 int32_t zversion = 0;
8576 int32_t zbuild = 0;
8577
8578 if(!p_igetl(&zversion,f))
8579 {
8580 return 0;
8581 }
8582 if(!p_igetl(&zbuild,f))
8583 {
8584 return 0;
8585 }
8586 if(!p_igetw(&section_version,f))
8587 {
8588 return 0;
8589 }
8590 if(!read_deprecated_section_cversion(f))
8591 {
8592 return 0;
8593 }
8594 al_trace("readoneweapon section_version: %d\n", section_version);
8595
8596 if ( zversion > ZELDA_VERSION )
8597 {
8598 al_trace("Cannot read .ztile packfile made in ZC version (%x) in this version of ZC (%x)\n", zversion, ZELDA_VERSION);
8599 return 0;
8600 }
8601
8602 else if ( ( section_version > V_TILES ))
8603 {
8604 al_trace("Cannot read .ztile packfile made using V_TILES (%d)\n", section_version);
8605 return 0;
8606
8607 }
8608 else
8609 {
8610 al_trace("Reading a .ztile packfile made in ZC Version: %x, Build: %d\n", zversion, zbuild);
8611 }
8612
8613 int32_t index = 0;
8614 int32_t count = 0;
8615
8616 //tile id
8617 if(!p_igetl(&index,f))
8618 {
8619 return 0;
8620 }
8621 al_trace("Reading tile: index(%d)\n", index);
8622
8623 //tile count
8624 if(!p_igetl(&count,f))
8625 {
8626 return 0;
8627 }
8628 al_trace("Reading tile: count(%d)\n", count);
8629
8630
8631
8632
8633 for ( int32_t tilect = 0; tilect < count; tilect++ )
8634 {
8635 byte *temp_tile = new byte[tilesize(tf32Bit)];
8636 byte format=tf4Bit;
8637 memset(temp_tile, 0, tilesize(tf32Bit));
8638 if(!p_getc(&format,f))
8639 {
8640 delete[] temp_tile;
8641 return 0;
8642 }
8643
8644
8645 if(!pfread(temp_tile,tilesize(format),f))
8646 {
8647 delete[] temp_tile;
8648 return 0;
8649 }
8650
8651 reset_tile(newtilebuf, index+(tilect), format);
8652 memcpy(newtilebuf[index+(tilect)].data,temp_tile,tilesize(newtilebuf[index+(tilect)].format));
8653 delete[] temp_tile;
8654 }
8655
8656
8657 //::memcpy(&(newtilebuf[tile_index]),&temptile,sizeof(tiledata));
8658
8659 register_blank_tiles();
8660 register_used_tiles();
8661
8662 return 1;
8663
8664 }
8665
8666 int32_t readtilefile_to_location(PACKFILE *f, int32_t start, int32_t skip)
8667 {
8668 dword section_version=0;
8669 int32_t zversion = 0;
8670 int32_t zbuild = 0;
8671
8672 if(!p_igetl(&zversion,f))
8673 {
8674 return 0;
8675 }
8676 if(!p_igetl(&zbuild,f))
8677 {
8678 return 0;
8679 }
8680 if(!p_igetw(&section_version,f))
8681 {
8682 return 0;
8683 }
8684 if(!read_deprecated_section_cversion(f))
8685 {
8686 return 0;
8687 }
8688 al_trace("readoneweapon section_version: %d\n", section_version);
8689
8690 if ( zversion > ZELDA_VERSION )
8691 {
8692 al_trace("Cannot read .ztile packfile made in ZC version (%x) in this version of ZC (%x)\n", zversion, ZELDA_VERSION);
8693 return 0;
8694 }
8695
8696 else if ( ( section_version > V_TILES ))
8697 {
8698 al_trace("Cannot read .ztile packfile made using V_TILES (%d)\n", section_version);
8699 return 0;
8700
8701 }
8702 else
8703 {
8704 al_trace("Reading a .ztile packfile made in ZC Version: %x, Build: %d\n", zversion, zbuild);
8705 }
8706
8707 int32_t index = 0;
8708 int32_t count = 0;
8709
8710 //tile id
8711 if(!p_igetl(&index,f))
8712 {
8713 return 0;
8714 }
8715 al_trace("Reading tile: index(%d)\n", index);
8716
8717 //tile count
8718 if(!p_igetl(&count,f))
8719 {
8720 return 0;
8721 }
8722 al_trace("Reading tile: count(%d)\n", count);
8723
8724
8725 for ( int32_t tilect = 0; tilect < count; tilect++ )
8726 {
8727 byte *temp_tile = new byte[tilesize(tf32Bit)];
8728 byte format=tf4Bit;
8729 memset(temp_tile, 0, tilesize(tf32Bit));
8730 if(!p_getc(&format,f))
8731 {
8732 delete[] temp_tile;
8733 return 0;
8734 }
8735
8736
8737 if(!pfread(temp_tile,tilesize(format),f))
8738 {
8739 delete[] temp_tile;
8740 return 0;
8741 }
8742
8743 reset_tile(newtilebuf, start+(tilect), format);
8744 if ( skip )
8745 {
8746 if ( (start+(tilect)) < skip )
8747 {
8748 delete[] temp_tile;
8749 continue;
8750 }
8751
8752 }
8753 if ( start+(tilect) < NEWMAXTILES )
8754 {
8755 memcpy(newtilebuf[start+(tilect)].data,temp_tile,tilesize(newtilebuf[start+(tilect)].format));
8756 }
8757 delete[] temp_tile;
8758
8759 }
8760
8761
8762 //::memcpy(&(newtilebuf[tile_index]),&temptile,sizeof(tiledata));
8763
8764 register_blank_tiles();
8765 register_used_tiles();
8766
8767 return 1;
8768
8769 }
8770
8771
8772 int32_t readtilefile_to_location(PACKFILE *f, int32_t start)
8773 {
8774 dword section_version=0;
8775 int32_t zversion = 0;
8776 int32_t zbuild = 0;
8777
8778 if(!p_igetl(&zversion,f))
8779 {
8780 return 0;
8781 }
8782 if(!p_igetl(&zbuild,f))
8783 {
8784 return 0;
8785 }
8786 if(!p_igetw(&section_version,f))
8787 {
8788 return 0;
8789 }
8790 if(!read_deprecated_section_cversion(f))
8791 {
8792 return 0;
8793 }
8794 al_trace("readoneweapon section_version: %d\n", section_version);
8795
8796 if ( zversion > ZELDA_VERSION )
8797 {
8798 al_trace("Cannot read .ztile packfile made in ZC version (%x) in this version of ZC (%x)\n", zversion, ZELDA_VERSION);
8799 return 0;
8800 }
8801
8802 else if ( ( section_version > V_TILES ))
8803 {
8804 al_trace("Cannot read .ztile packfile made using V_TILES (%d)\n", section_version);
8805 return 0;
8806
8807 }
8808 else
8809 {
8810 al_trace("Reading a .ztile packfile made in ZC Version: %x, Build: %d\n", zversion, zbuild);
8811 }
8812
8813 int32_t index = 0;
8814 int32_t count = 0;
8815
8816 //tile id
8817 if(!p_igetl(&index,f))
8818 {
8819 return 0;
8820 }
8821 al_trace("Reading tile: index(%d)\n", index);
8822
8823 //tile count
8824 if(!p_igetl(&count,f))
8825 {
8826 return 0;
8827 }
8828 al_trace("Reading tile: count(%d)\n", count);
8829
8830
8831
8832
8833 for ( int32_t tilect = 0; tilect < count; tilect++ )
8834 {
8835 byte *temp_tile = new byte[tilesize(tf32Bit)];
8836 byte format=tf4Bit;
8837 memset(temp_tile, 0, tilesize(tf32Bit));
8838
8839 if(!p_getc(&format,f))
8840 {
8841 delete[] temp_tile;
8842 return 0;
8843 }
8844
8845
8846 if(!pfread(temp_tile,tilesize(format),f))
8847 {
8848 delete[] temp_tile;
8849 return 0;
8850 }
8851
8852 reset_tile(newtilebuf, start+(tilect), format);
8853 if ( start+(tilect) < NEWMAXTILES )
8854 {
8855 memcpy(newtilebuf[start+(tilect)].data,temp_tile,tilesize(newtilebuf[start+(tilect)].format));
8856 }
8857 delete[] temp_tile;
8858 }
8859
8860
8861 //::memcpy(&(newtilebuf[tile_index]),&temptile,sizeof(tiledata));
8862
8863 register_blank_tiles();
8864 register_used_tiles();
8865
8866 return 1;
8867
8868 }
8869 int32_t writetilefile(PACKFILE *f, int32_t index, int32_t count)
8870 {
8871 dword section_version=V_TILES;
8872 int32_t zversion = ZELDA_VERSION;
8873 int32_t zbuild = VERSION_BUILD;
8874
8875 if(!p_iputl(zversion,f))
8876 {
8877 return 0;
8878 }
8879 if(!p_iputl(zbuild,f))
8880 {
8881 return 0;
8882 }
8883 if(!p_iputw(section_version,f))
8884 {
8885 return 0;
8886 }
8887
8888 if(!write_deprecated_section_cversion(section_version,f))
8889 {
8890 return 0;
8891 }
8892
8893 //start tile id
8894 if(!p_iputl(index,f))
8895 {
8896 return 0;
8897 }
8898
8899 //count
8900 if(!p_iputl(count,f))
8901 {
8902 return 0;
8903 }
8904
8905 for ( int32_t tilect = 0; tilect < count; tilect++ )
8906 {
8907 if(!p_putc(newtilebuf[index+(tilect)].format,f))
8908 {
8909 return 0;
8910 }
8911 if(!pfwrite(newtilebuf[index+(tilect)].data,tilesize(newtilebuf[index+(tilect)].format),f))
8912 {
8913 return 0;
8914 }
8915 }
8916
8917 return 1;
8918
8919 }
8920
8921 static int32_t _selected_tile=-1, _selected_tcset=-1;
8922 int32_t select_tile(int32_t &tile,int32_t &flip,int32_t type,int32_t &cs,bool edit_cs,int32_t exnow, bool always_use_flip)
8923 {
8924 popup_zqdialog_start();
8925 reset_combo_animations();
8926 reset_combo_animations2();
8927 bound(tile,0,NEWMAXTILES-1);
8928 ex=exnow;
8929 int32_t done=0;
8930 int32_t oflip=flip;
8931 int32_t otile=tile;
8932 int32_t ocs=cs;
8933 int32_t first=(tile/TILES_PER_PAGE)*TILES_PER_PAGE; //first tile on the current page
8934 int32_t copy=-1;
8935 int32_t tile2=tile,copycnt=0;
8936 reftile = 0;
8937 int32_t tile_clicked=-1;
8938 bool rect_sel=true;
8939 bound(first,0,(TILES_PER_PAGE*TILE_PAGES)-1);
8940 position_mouse_z(0);
8941
8942 register_used_tiles();
8943 int32_t w = 640;
8944 int32_t h = 480;
8945 int32_t window_xofs=(zq_screen_w-w-12)>>1;
8946 int32_t window_yofs=(zq_screen_h-h-25-6)>>1;
8947 int32_t screen_xofs=window_xofs+6;
8948 int32_t screen_yofs=window_yofs+25;
8949 int32_t panel_yofs=3;
8950 int32_t mul = 2;
8951 FONT *tfont = get_zc_font(font_lfont_l);
8952
8953 draw_tile_list_window();
8954 draw_tiles(first,cs);
8955
8956 if(type==0)
8957 {
8958 tile_info_0(tile,tile2,cs,copy,copycnt,first/TILES_PER_PAGE,rect_sel);
8959 }
8960 else
8961 {
8962 tile_info_1(otile,oflip,ocs,tile,flip,cs,copy,first/TILES_PER_PAGE, always_use_flip);
8963 }
8964 anim_hw_screen();
8965
8966 go_tiles();
8967
8968 while(gui_mouse_b()) ; // wait
8969
8970 bool bdown=false;
8971
8972 #define FOREACH_START(_t) \
8973 { \
8974 int32_t _first, _last; \
8975 if(is_rect) \
8976 { \
8977 _first=top*TILES_PER_ROW+left; \
8978 _last=_first+rows*TILES_PER_ROW|+columns-1; \
8979 } \
8980 else \
8981 { \
8982 _first=zc_min(tile, tile2); \
8983 _last=zc_max(tile, tile2); \
8984 } \
8985 for(int32_t _t=_first; _t<=_last; _t++) \
8986 { \
8987 if(is_rect) \
8988 { \
8989 int32_t row=TILEROW(_t); \
8990 if(row<top || row>=top+rows) \
8991 continue; \
8992 int32_t col=TILECOL(_t); \
8993 if(col<left || col>=left+columns) \
8994 continue; \
8995 } \
8996
8997 #define FOREACH_END\
8998 } \
8999 }
9000
9001 bool did_snap = false;
9002 int otl = tile, otl2 = tile2;
9003 do
9004 {
9005 HANDLE_CLOSE_ZQDLG();
9006 if(exiting_program) break;
9007 //rest(4);
9008 int32_t top=TILEROW(zc_min(tile, tile2));
9009 int32_t left=zc_min(TILECOL(tile), TILECOL(tile2));
9010 int32_t rows=TILEROW(zc_max(tile, tile2))-top+1;
9011 int32_t columns=zc_max(TILECOL(tile), TILECOL(tile2))-left+1;
9012 bool is_rect=(rows==1)||(columns==TILES_PER_ROW)||rect_sel;
9013 bool redraw=false;
9014
9015 if(mouse_z!=0)
9016 {
9017 sel_tile(tile,tile2,first,type,((mouse_z/abs(mouse_z))*(-1)*TILES_PER_PAGE));
9018 position_mouse_z(0);
9019 redraw=true;
9020 }
9021
9022 if(keypressed())
9023 {
9024 switch(readkey()>>8)
9025 {
9026 case KEY_ENTER_PAD:
9027 case KEY_ENTER:
9028 done=2;
9029 break;
9030
9031 case KEY_ESC:
9032 done=1;
9033 break;
9034
9035 case KEY_F1:
9036 onHelp();
9037 break;
9038
9039 case KEY_EQUALS:
9040 case KEY_PLUS_PAD:
9041 {
9042 if(CHECK_CTRL_CMD ||
9043 key[KEY_ALT] || key[KEY_ALTGR])
9044 {
9045 FOREACH_START(t)
9046 if(key[KEY_ALT] || key[KEY_ALTGR])
9047 shift_tile_colors(t, 16, false);
9048 else
9049 shift_tile_colors(t, 1, key[KEY_LSHIFT] || key[KEY_RSHIFT]);
9050 FOREACH_END
9051
9052 register_blank_tiles();
9053 }
9054 else if(edit_cs)
9055 cs = (cs<13) ? cs+1:0;
9056
9057 redraw=true;
9058 break;
9059 }
9060
9061 case KEY_Z:
9062 case KEY_F12:
9063 {
9064 if(!did_snap)
9065 {
9066 //Export tile page as screenshot
9067 PALETTE temppal;
9068 get_palette(temppal);
9069 BITMAP *tempbmp=create_bitmap_ex(8,16*TILES_PER_ROW, 16*TILE_ROWS_PER_PAGE);
9070 draw_tiles(tempbmp,first,cs,false,true);
9071 save_bitmap(getSnapName(), tempbmp, RAMpal);
9072 destroy_bitmap(tempbmp);
9073
9074 redraw = true;
9075 did_snap = true;
9076 }
9077 break;
9078 }
9079
9080 case KEY_S:
9081 {
9082 if(!prompt_for_new_file_compat("Save ZTILE(.ztile)", "ztile", NULL,datapath,false))
9083 break;
9084 PACKFILE *f=pack_fopen_password(temppath,F_WRITE, "");
9085 if(!f) break;
9086 al_trace("Saving tile: %d\n", tile);
9087 writetilefile(f,tile,1);
9088 pack_fclose(f);
9089 break;
9090 }
9091 case KEY_L:
9092 {
9093 if(!prompt_for_existing_file_compat("Load ZTILE(.ztile)", "ztile", NULL,datapath,false))
9094 break;
9095 PACKFILE *f=pack_fopen_password(temppath,F_READ, "");
9096 if(!f) break;
9097 al_trace("Saving tile: %d\n", tile);
9098 if (!readtilefile(f))
9099 {
9100 al_trace("Could not read from .ztile packfile %s\n", temppath);
9101 jwin_alert("ZTILE File: Error","Could not load the specified Tile.",NULL,NULL,"O&K",NULL,'k',0,get_zc_font(font_lfont));
9102 }
9103 else
9104 {
9105 jwin_alert("ZTILE File: Success!","Loaded the source tiles to your tile sheets!",NULL,NULL,"O&K",NULL,'k',0,get_zc_font(font_lfont));
9106 }
9107
9108 pack_fclose(f);
9109 //register_blank_tiles();
9110 //register_used_tiles();
9111 redraw=true;
9112 break;
9113 }
9114 case KEY_MINUS:
9115 case KEY_MINUS_PAD:
9116 {
9117 if(CHECK_CTRL_CMD ||
9118 key[KEY_ALT] || key[KEY_ALTGR])
9119 {
9120 FOREACH_START(t)
9121 if(key[KEY_ALT] || key[KEY_ALTGR])
9122 shift_tile_colors(t, -16, false);
9123 else
9124 shift_tile_colors(t, -1, key[KEY_LSHIFT] || key[KEY_RSHIFT]);
9125 FOREACH_END
9126
9127 register_blank_tiles();
9128 }
9129 else if(edit_cs)
9130 cs = (cs>0) ? cs-1:13;
9131
9132 redraw=true;
9133 break;
9134 }
9135
9136 case KEY_UP:
9137 {
9138 switch(((key[KEY_ALT] || key[KEY_ALTGR])?2:0)+((CHECK_CTRL_CMD)?1:0))
9139 {
9140 case 3: //ALT and CTRL
9141 case 2: //ALT
9142 if(is_rect)
9143 {
9144 mark_save_dirty();
9145 go_slide_tiles(columns, rows, top, left);
9146 int32_t bitcheck = newtilebuf[((top)*TILES_PER_ROW)+left].format;
9147 bool same = true;
9148
9149 for(int32_t d=0; d<columns; d++)
9150 {
9151 for(int32_t s=0; s<rows; s++)
9152 {
9153 int32_t t=((top+s)*TILES_PER_ROW)+left+d;
9154
9155 if(newtilebuf[t].format!=bitcheck) same = false;
9156 }
9157 }
9158
9159 if(!same) break;
9160
9161 // This used to do something. Too lazy to remove.
9162 // Can probably remove the above "same" check too.
9163 bitcheck = 2;
9164
9165 for(int32_t c=0; c<columns; c++)
9166 {
9167 for(int32_t r=0; r<rows; r++)
9168 {
9169 int32_t temptile=((top+r)*TILES_PER_ROW)+left+c;
9170 qword *src_pixelrow=(qword*)(newundotilebuf[temptile].data+(8*bitcheck));
9171 qword *dest_pixelrow=(qword*)(newtilebuf[temptile].data);
9172
9173 for(int32_t pixelrow=0; pixelrow<16*bitcheck; pixelrow++)
9174 {
9175 if(pixelrow==15*bitcheck)
9176 {
9177 int32_t srctile=temptile+TILES_PER_ROW;
9178 if(srctile>=NEWMAXTILES)
9179 srctile-=rows*TILES_PER_ROW;
9180 src_pixelrow=(qword*)(newtilebuf[srctile].data);
9181 }
9182
9183 *dest_pixelrow=*src_pixelrow;
9184 dest_pixelrow++;
9185 src_pixelrow++;
9186 }
9187 }
9188
9189 qword *dest_pixelrow=(qword*)(newtilebuf[((top+rows-1)*TILES_PER_ROW)+left+c].data+(120*bitcheck));
9190
9191 for(int32_t b=0; b<bitcheck; b++,dest_pixelrow++)
9192 {
9193 if((CHECK_CTRL_CMD))
9194 {
9195 *dest_pixelrow=0;
9196 }
9197 else
9198 {
9199 qword *src_pixelrow=(qword*)(newundotilebuf[(top*TILES_PER_ROW)+left+c].data+(8*b));
9200 *dest_pixelrow=*src_pixelrow;
9201 }
9202 }
9203 }
9204 }
9205
9206 register_blank_tiles();
9207 redraw=true;
9208 break;
9209
9210 case 1: //CTRL
9211 case 0: //None
9212 sel_tile(tile,tile2,first,type,(CHECK_CTRL_CMD)?-1*(tile_page_row(tile)*TILES_PER_ROW):-TILES_PER_ROW);
9213 redraw=true;
9214
9215 default: //Others
9216 break;
9217 }
9218 }
9219 break;
9220
9221 case KEY_DOWN:
9222 {
9223 switch(((key[KEY_ALT] || key[KEY_ALTGR])?2:0)+((CHECK_CTRL_CMD)?1:0))
9224 {
9225 case 3: //ALT and CTRL
9226 case 2: //ALT
9227 if(is_rect)
9228 {
9229 mark_save_dirty();
9230 go_slide_tiles(columns, rows, top, left);
9231 int32_t bitcheck = newtilebuf[((top)*TILES_PER_ROW)+left].format;
9232 bool same = true;
9233
9234 for(int32_t c=0; c<columns; c++)
9235 {
9236 for(int32_t r=0; r<rows; r++)
9237 {
9238 int32_t t=((top+r)*TILES_PER_ROW)+left+c;
9239
9240 if(newtilebuf[t].format!=bitcheck) same = false;
9241 }
9242 }
9243
9244 if(!same) break;
9245
9246 // This used to do something. Too lazy to remove.
9247 // Can probably remove the above "same" check too.
9248 bitcheck = 2;
9249
9250 for(int32_t c=0; c<columns; c++)
9251 {
9252 for(int32_t r=rows-1; r>=0; r--)
9253 {
9254 int32_t temptile=((top+r)*TILES_PER_ROW)+left+c;
9255 qword *src_pixelrow=(qword*)(newundotilebuf[temptile].data+(112*bitcheck)+(8*(bitcheck-1)));
9256 qword *dest_pixelrow=(qword*)(newtilebuf[temptile].data+(120*bitcheck)+(8*(bitcheck-1)));
9257
9258 for(int32_t pixelrow=(8<<bitcheck)-1; pixelrow>=0; pixelrow--)
9259 {
9260 if(pixelrow<bitcheck)
9261 {
9262 int32_t srctile=temptile-TILES_PER_ROW;
9263 if(srctile<0)
9264 srctile+=rows*TILES_PER_ROW;
9265 qword *tempsrc=(qword*)(newtilebuf[srctile].data+(120*bitcheck)+(8*pixelrow));
9266 *dest_pixelrow=*tempsrc;
9267 //*dest_pixelrow=0;
9268 }
9269 else
9270 {
9271 *dest_pixelrow=*src_pixelrow;
9272 }
9273
9274 dest_pixelrow--;
9275 src_pixelrow--;
9276 }
9277 }
9278
9279 qword *dest_pixelrow=(qword*)(newtilebuf[(top*TILES_PER_ROW)+left+c].data);
9280 qword *src_pixelrow=(qword*)(newundotilebuf[((top+rows-1)*TILES_PER_ROW)+left+c].data+(120*bitcheck));
9281
9282 for(int32_t b=0; b<bitcheck; b++)
9283 {
9284 if((CHECK_CTRL_CMD))
9285 {
9286 *dest_pixelrow=0;
9287 }
9288 else
9289 {
9290 *dest_pixelrow=*src_pixelrow;
9291 }
9292
9293 dest_pixelrow++;
9294 src_pixelrow++;
9295 }
9296 }
9297 }
9298
9299 register_blank_tiles();
9300 redraw=true;
9301 break;
9302
9303 case 1: //CTRL
9304 case 0: //None
9305 sel_tile(tile,tile2,first,type,(CHECK_CTRL_CMD)?((TILE_ROWS_PER_PAGE-1)-tile_page_row(tile))*TILES_PER_ROW:TILES_PER_ROW);
9306 redraw=true;
9307
9308 default: //Others
9309 break;
9310 }
9311 }
9312 break;
9313
9314 case KEY_LEFT:
9315 {
9316 switch(((key[KEY_ALT] || key[KEY_ALTGR])?2:0)+((CHECK_CTRL_CMD)?1:0))
9317 {
9318 case 3: //ALT and CTRL
9319 case 2: //ALT
9320 if(is_rect)
9321 {
9322 mark_save_dirty();
9323 go_slide_tiles(columns, rows, top, left);
9324 int32_t bitcheck = newtilebuf[((top)*TILES_PER_ROW)+left].format;
9325 bool same = true;
9326
9327 for(int32_t c=0; c<columns; c++)
9328 {
9329 for(int32_t r=0; r<rows; r++)
9330 {
9331 int32_t t=((top+r)*TILES_PER_ROW)+left+c;
9332
9333 if(newtilebuf[t].format!=bitcheck) same = false;
9334 }
9335 }
9336
9337 if(!same) break;
9338
9339 // This used to do something. Too lazy to remove.
9340 // Can probably remove the above "same" check too.
9341 bitcheck = 2;
9342
9343 for(int32_t r=0; r<rows; r++)
9344 {
9345 for(int32_t c=0; c<columns; c++)
9346 {
9347 int32_t temptile=((top+r)*TILES_PER_ROW)+left+c;
9348 byte *dest_pixelrow=(newtilebuf[temptile].data);
9349
9350 for(int32_t pixelrow=0; pixelrow<16; pixelrow++)
9351 {
9352 for(int32_t p=0; p<(8*bitcheck)-1; p++)
9353 {
9354 *dest_pixelrow=*(dest_pixelrow+1);
9355 dest_pixelrow++;
9356 }
9357
9358 if(c==columns-1)
9359 {
9360 if(!(CHECK_CTRL_CMD))
9361 {
9362 byte *tempsrc=(newundotilebuf[((top+r)*TILES_PER_ROW)+left].data+(pixelrow*8*bitcheck));
9363 *dest_pixelrow=*tempsrc;
9364 }
9365 }
9366 else
9367
9368 {
9369 byte *tempsrc=(newtilebuf[temptile+1].data+(pixelrow*8*bitcheck));
9370 *dest_pixelrow=*tempsrc;
9371 }
9372
9373 dest_pixelrow++;
9374 }
9375 }
9376 }
9377
9378 register_blank_tiles();
9379 redraw=true;
9380 }
9381
9382 break;
9383
9384 case 1: //CTRL
9385 case 0: //None
9386 sel_tile(tile,tile2,first,type,(CHECK_CTRL_CMD)?-(tile%TILES_PER_ROW):-1);
9387 redraw=true;
9388
9389 default: //Others
9390 break;
9391 }
9392 }
9393 break;
9394
9395 case KEY_RIGHT:
9396 {
9397 switch(((key[KEY_ALT] || key[KEY_ALTGR])?2:0)+((CHECK_CTRL_CMD)?1:0))
9398 {
9399 case 3: //ALT and CTRL
9400 case 2: //ALT
9401 if(is_rect)
9402 {
9403 mark_save_dirty();
9404 go_slide_tiles(columns, rows, top, left);
9405 int32_t bitcheck = newtilebuf[((top)*TILES_PER_ROW)+left].format;
9406 bool same = true;
9407
9408 for(int32_t c=0; c<columns; c++)
9409 {
9410 for(int32_t r=0; r<rows; r++)
9411 {
9412 int32_t t=((top+r)*TILES_PER_ROW)+left+c;
9413
9414 if(newtilebuf[t].format!=bitcheck) same = false;
9415 }
9416 }
9417
9418 if(!same) break;
9419
9420 // This used to do something. Too lazy to remove.
9421 // Can probably remove the above "same" check too.
9422 bitcheck = 2;
9423
9424 for(int32_t r=0; r<rows; r++)
9425 {
9426 for(int32_t c=columns-1; c>=0; c--)
9427 {
9428 int32_t temptile=((top+r)*TILES_PER_ROW)+left+c;
9429 byte *dest_pixelrow=(newtilebuf[temptile].data)+(128*bitcheck)-1;
9430
9431 for(int32_t pixelrow=15; pixelrow>=0; pixelrow--)
9432 {
9433 for(int32_t p=0; p<(8*bitcheck)-1; p++)
9434 {
9435 *dest_pixelrow=*(dest_pixelrow-1);
9436 dest_pixelrow--;
9437 }
9438
9439 if(c==0)
9440 {
9441 if(!(CHECK_CTRL_CMD))
9442 {
9443 byte *tempsrc=(newundotilebuf[(((top+r)*TILES_PER_ROW)+left+columns-1)].data+(pixelrow*8*bitcheck)+(8*bitcheck)-1);
9444 *dest_pixelrow=*tempsrc;
9445 }
9446 }
9447 else
9448 {
9449 byte *tempsrc=(newtilebuf[temptile-1].data+(pixelrow*8*bitcheck)+(8*bitcheck)-1);
9450 *dest_pixelrow=*tempsrc;
9451 }
9452
9453 dest_pixelrow--;
9454 }
9455 }
9456 }
9457
9458 register_blank_tiles();
9459 redraw=true;
9460 }
9461
9462 break;
9463
9464 case 1: //CTRL
9465 case 0: //None
9466 sel_tile(tile,tile2,first,type,(CHECK_CTRL_CMD)?(TILES_PER_ROW)-(tile%TILES_PER_ROW)-1:1);
9467 redraw=true;
9468
9469 default: //Others
9470 break;
9471 }
9472 }
9473 break;
9474
9475 case KEY_PGUP:
9476 sel_tile(tile,tile2,first,type,(CHECK_CTRL_CMD)?-1*(TILEROW(tile)*TILES_PER_ROW):-TILES_PER_PAGE);
9477 redraw=true;
9478 break;
9479
9480 case KEY_PGDN:
9481 sel_tile(tile,tile2,first,type,(CHECK_CTRL_CMD)?((TILE_PAGES*TILE_ROWS_PER_PAGE)-TILEROW(tile)-1)*TILES_PER_ROW:TILES_PER_PAGE);
9482 redraw=true;
9483 break;
9484
9485 case KEY_HOME:
9486 sel_tile(tile,tile2,first,type,(CHECK_CTRL_CMD)?-(tile):-(tile%TILES_PER_PAGE));
9487 redraw=true;
9488 break;
9489
9490 case KEY_END:
9491 sel_tile(tile,tile2,first,type,(CHECK_CTRL_CMD)?(TILE_PAGES)*(TILES_PER_PAGE)-tile-1:(TILES_PER_PAGE)-(tile%TILES_PER_PAGE)-1);
9492 redraw=true;
9493 break;
9494
9495 case KEY_P:
9496 {
9497 int32_t whatPage = gettilepagenumber("Goto Page", (PreFillTileEditorPage?(first/TILES_PER_PAGE):0));
9498
9499 if(whatPage >= 0)
9500 sel_tile(tile,tile2,first,type,((whatPage-TILEPAGE(tile))*TILE_ROWS_PER_PAGE)*TILES_PER_ROW);
9501
9502 break;
9503 }
9504
9505 case KEY_O:
9506 if(type==0 && copy>=0)
9507 {
9508 go_tiles();
9509
9510 if(key[KEY_LSHIFT] ||key[KEY_RSHIFT])
9511 {
9512 mass_overlay_tile(zc_min(tile,tile2),zc_max(tile,tile2),copy,cs,(CHECK_CTRL_CMD), rect_sel);
9513 mark_save_dirty();
9514 }
9515 else
9516 {
9517 if (overlay_tiles(tile,tile2,copy,copycnt,rect_sel,false,cs,(CHECK_CTRL_CMD)))
9518 mark_save_dirty();
9519 //overlay_tile(newtilebuf,tile,copy,cs,(CHECK_CTRL_CMD));
9520 }
9521
9522 mark_save_dirty();
9523 redraw=true;
9524 }
9525
9526 break;
9527
9528 case KEY_E:
9529 if(type==0)
9530 {
9531 edit_tile(tile,flip,cs);
9532 draw_tile_list_window();
9533 redraw=true;
9534 }
9535
9536 break;
9537
9538 case KEY_G:
9539 if(type==0)
9540 {
9541 grab_tile(tile,cs);
9542 draw_tile_list_window();
9543 redraw=true;
9544 }
9545
9546 break;
9547
9548 case KEY_C:
9549 copy=zc_min(tile,tile2);
9550 copycnt=abs(tile-tile2)+1;
9551 redraw=true;
9552 break;
9553
9554 case KEY_X:
9555 if(type==2)
9556 {
9557 ex=(ex+1)%3;
9558 }
9559
9560 break;
9561
9562 case KEY_R:
9563 if(type==2)
9564 break;
9565 if(type==1)
9566 {
9567 flip = rotate_value(flip);
9568 redraw=true;
9569 break;
9570 }
9571
9572 go_tiles();
9573
9574 if(CHECK_CTRL_CMD)
9575 {
9576 bool go=false;
9577 if(key[KEY_LSHIFT] || key[KEY_RSHIFT])
9578 go=true;
9579 else if(massRecolorSetup(cs))
9580 go=true;
9581
9582 if(go)
9583 {
9584 FOREACH_START(t)
9585 massRecolorApply(t);
9586 FOREACH_END
9587
9588 register_blank_tiles();
9589 }
9590 }
9591 else
9592 {
9593 FOREACH_START(t)
9594 rotate_tile(t,(key[KEY_LSHIFT] || key[KEY_RSHIFT]));
9595 FOREACH_END
9596 }
9597
9598 redraw=true;
9599 mark_save_dirty();
9600 break;
9601
9602 case KEY_SPACE:
9603 rect_sel=!rect_sel;
9604 copy=-1;
9605 redraw=true;
9606 break;
9607
9608 case KEY_H:
9609 flip^=1;
9610 go_tiles();
9611
9612 if(type==0)
9613 {
9614 normalize(tile,tile2,rect_sel,flip);
9615 flip=0;
9616 }
9617
9618 redraw=true;
9619 break;
9620
9621
9622 case KEY_V:
9623 if(copy==-1)
9624 {
9625 if(type!=2)
9626 {
9627 flip^=2;
9628 go_tiles();
9629
9630 if(type==0)
9631 {
9632 normalize(tile,tile2,rect_sel,flip);
9633 flip=0;
9634 }
9635 }
9636 }
9637 else
9638 {
9639 bool alt=(key[KEY_ALT] || key[KEY_ALTGR]);
9640 go_tiles();
9641 if (copy_tiles(tile,tile2,copy,copycnt,rect_sel,false))
9642 mark_save_dirty();
9643 }
9644
9645 redraw=true;
9646 break;
9647
9648 case KEY_F:
9649 if(copy==-1)
9650 {
9651 break;
9652 }
9653 else
9654 {
9655 go_tiles();
9656 {
9657 if (copy_tiles_floodfill(tile,tile2,copy,copycnt,rect_sel,false))
9658 mark_save_dirty();
9659 }
9660 }
9661
9662 redraw=true;
9663 break;
9664
9665 case KEY_DEL:
9666 if(type==0 && (key[KEY_LSHIFT]||key[KEY_RSHIFT]))
9667 {
9668 bool warn = (rect_sel
9669 && ((tile/20)!=(tile2/20))
9670 && !(tile%20==0&&tile2%20==19));
9671 int32_t z=zc_min(tile,tile2);
9672 int32_t count = abs(tile-tile2) + 1;
9673 tile=z;
9674 tile2=NEWMAXTILES;
9675 copy = tile + count;
9676 copycnt = NEWMAXTILES-copy;
9677 char buf[64];
9678
9679 if(count>1)
9680 sprintf(buf,"Remove tiles %d - %d?",tile, copy-1);
9681 else
9682 sprintf(buf,"Remove tile %d?",tile);
9683
9684 AlertDialog("Remove Tiles", std::string(buf)
9685 +"\nThis will offset the tiles that follow!"
9686 +(warn?"\nRemoving tiles ignores rectangular selections!":""),
9687 [&](bool ret,bool)
9688 {
9689 if(ret)
9690 {
9691 go_tiles();
9692 if(copy_tiles(tile,tile2,copy,copycnt,false,true))
9693 {
9694 redraw=true;
9695 mark_save_dirty();
9696 }
9697 }
9698 }).show();
9699 }
9700 delete_tiles(tile,tile2,rect_sel);
9701 redraw=true;
9702 break;
9703
9704 case KEY_U:
9705 {
9706 if(CHECK_CTRL_CMD)
9707 {
9708 //Only toggle the first 2 bits!
9709 show_only_unused_tiles = (show_only_unused_tiles&~3) | (((show_only_unused_tiles&3)+1)%4);
9710 }
9711 else
9712 {
9713 comeback_tiles();
9714 }
9715
9716 redraw=true;
9717 }
9718 break;
9719
9720 case KEY_8:
9721 case KEY_8_PAD:
9722 hide_8bit_marker();
9723 break;
9724
9725 case KEY_I: //insert tiles
9726 if(type==0)
9727 {
9728 bool warn = (rect_sel
9729 && ((tile/20)!=(tile2/20))
9730 && !(tile%20==0&&tile2%20==19));
9731 int32_t z=zc_min(tile,tile2);
9732 int32_t count = abs(tile-tile2) + 1;
9733 tile=z;
9734 tile2=NEWMAXTILES;
9735 copy = tile + count;
9736 copycnt = NEWMAXTILES-copy;
9737
9738 if(key[KEY_LSHIFT]||key[KEY_RSHIFT]) //Remove
9739 {
9740 char buf[64];
9741
9742 if(count>1)
9743 sprintf(buf,"Remove tiles %d - %d?",tile, copy-1);
9744 else
9745 sprintf(buf,"Remove tile %d?",tile);
9746
9747 AlertDialog("Remove Tiles", std::string(buf)
9748 +"\nThis will offset the tiles that follow!"
9749 +(warn?"\nRemoving tiles ignores rectangular selections!":""),
9750 [&](bool ret,bool)
9751 {
9752 if(ret)
9753 {
9754 go_tiles();
9755 if(copy_tiles(tile,tile2,copy,copycnt,false,true))
9756 {
9757 redraw=true;
9758 mark_save_dirty();
9759 }
9760 }
9761 }).show();
9762 }
9763 else
9764 {
9765 char buf[64];
9766
9767 if(count>1)
9768 sprintf(buf,"Insert %d blank tiles?",count);
9769 else
9770 sprintf(buf,"Insert a blank tile?");
9771
9772 AlertDialog("Insert Tiles", std::string(buf)
9773 +"\nThis will offset the tiles that follow!"
9774 +(warn?"\nInserting tiles ignores rectangular selections!":""),
9775 [&](bool ret,bool)
9776 {
9777 if(ret)
9778 {
9779 go_tiles();
9780 if(copy_tiles(copy,tile2,tile,copycnt,false,true))
9781 {
9782 redraw=true;
9783 mark_save_dirty();
9784 }
9785 }
9786 }).show();
9787 }
9788
9789 copy=-1;
9790 tile2=tile=z;
9791 }
9792 break;
9793 case KEY_M:
9794 if(type==0)
9795 {
9796 if((copy!=-1)&&(copy!=zc_min(tile,tile2)))
9797 {
9798 go_tiles();
9799 if(copy_tiles(tile,tile2,copy,copycnt,rect_sel,true))
9800 mark_save_dirty();
9801 }
9802 else if(copy==-1)
9803 {
9804 // I don't know what this was supposed to be doing before.
9805 // It didn't work in anything like a sensible way.
9806 if(rect_sel)
9807 {
9808 make_combos_rect(top, left, rows, columns, cs);
9809 }
9810 else
9811 {
9812 make_combos(zc_min(tile, tile2), zc_max(tile, tile2), cs);
9813 }
9814 }
9815
9816 redraw=true;
9817 }
9818 break;
9819
9820 case KEY_D:
9821 {
9822 int32_t frames=1;
9823 char buf[80];
9824 sprintf(buf, "%d", frames);
9825 create_relational_tiles_dlg[0].dp2=get_zc_font(font_lfont);
9826 create_relational_tiles_dlg[2].dp=buf;
9827
9828 large_dialog(create_relational_tiles_dlg);
9829
9830 int32_t ret=do_zqdialog(create_relational_tiles_dlg,2);
9831
9832 if(ret==5)
9833 {
9834 frames=zc_max(atoi(buf),1);
9835 bool same = true;
9836 int32_t bitcheck=newtilebuf[tile].format;
9837
9838 for(int32_t t=1; t<frames*(create_relational_tiles_dlg[3].flags&D_SELECTED?6:19); ++t)
9839 {
9840 if(newtilebuf[tile+t].format!=bitcheck) same = false;
9841 }
9842
9843 if(!same)
9844 {
9845 jwin_alert("Error","The source tiles are not","in the same format.",NULL,"&OK",NULL,13,27,get_zc_font(font_lfont));
9846 break;
9847 }
9848
9849 if(tile+(frames*(create_relational_tiles_dlg[3].flags&D_SELECTED?48:96))>NEWMAXTILES)
9850 {
9851 jwin_alert("Error","Too many tiles will be created",NULL,NULL,"&OK",NULL,13,27,get_zc_font(font_lfont));
9852 break;
9853 }
9854
9855 for(int32_t i=frames*(create_relational_tiles_dlg[3].flags&D_SELECTED?6:19); i<(frames*(create_relational_tiles_dlg[3].flags&D_SELECTED?48:96)); ++i)
9856 {
9857 reset_tile(newtilebuf, tile+i, bitcheck);
9858 }
9859
9860 if(create_relational_tiles_dlg[3].flags&D_SELECTED)
9861 {
9862 for(int32_t i=create_relational_tiles_dlg[3].flags&D_SELECTED?47:95; i>0; --i)
9863 {
9864 for(int32_t j=0; j<frames; ++j)
9865 {
9866 merge_tiles(tile+(i*frames)+j, (tile+(relational_template[i][0]*frames)+j)<<2, ((tile+(relational_template[i][1]*frames)+j)<<2)+1, ((tile+(relational_template[i][2]*frames)+j)<<2)+2, ((tile+(relational_template[i][3]*frames)+j)<<2)+3);
9867 }
9868 }
9869 }
9870 else
9871 {
9872 for(int32_t i=create_relational_tiles_dlg[3].flags&D_SELECTED?47:95; i>0; --i)
9873 {
9874 for(int32_t j=0; j<frames; ++j)
9875 {
9876 merge_tiles(tile+(i*frames)+j, (tile+(dungeon_carving_template[i][0]*frames)+j)<<2, ((tile+(dungeon_carving_template[i][1]*frames)+j)<<2)+1, ((tile+(dungeon_carving_template[i][2]*frames)+j)<<2)+2, ((tile+(dungeon_carving_template[i][3]*frames)+j)<<2)+3);
9877 }
9878 }
9879 }
9880 }
9881 register_blank_tiles();
9882 register_used_tiles();
9883 redraw=true;
9884 mark_save_dirty();
9885 break;
9886 }
9887
9888 case KEY_B:
9889 {
9890 bool shift=(key[KEY_LSHIFT] || key[KEY_RSHIFT]);
9891 bool control=(CHECK_CTRL_CMD);
9892 bool alt=(key[KEY_ALT] || key[KEY_ALTGR]);
9893 int format = control ? tf4Bit : tf8Bit;
9894
9895 do_convert_tile(tile, tile2, cs, rect_sel, format, shift, alt);
9896 register_blank_tiles();
9897 }
9898 break;
9899 }
9900
9901 clear_keybuf();
9902 }
9903
9904 if(!(key[KEY_Z] || key[KEY_F12]))
9905 did_snap = false;
9906
9907 if(gui_mouse_b()&1)
9908 {
9909 if(isinRect(gui_mouse_x(),gui_mouse_y(),window_xofs + w + 12 - 21, window_yofs + 5, window_xofs + w +12 - 21 + 15, window_yofs + 5 + 13))
9910 {
9911 if(do_x_button(screen, w+12+window_xofs - 21, 5+window_yofs))
9912 {
9913 done=1;
9914 }
9915 }
9916
9917 int32_t x=gui_mouse_x()-screen_xofs;
9918 int32_t y=gui_mouse_y()-screen_yofs;
9919
9920 if(y>=0 && y<208*mul)
9921 {
9922 x=zc_min(zc_max(x,0),(320*mul)-1);
9923 int32_t t = (y>>(5))*TILES_PER_ROW + (x>>(5)) + first;
9924
9925 if(type==0 && (key[KEY_LSHIFT] || key[KEY_RSHIFT]))
9926 {
9927 tile2=t;
9928 }
9929 else
9930 {
9931 tile=tile2=t;
9932 }
9933
9934 if(tile_clicked!=t)
9935 {
9936 dclick_status=DCLICK_NOT;
9937 }
9938 else if(dclick_status == DCLICK_AGAIN)
9939 {
9940 while(gui_mouse_b()) ; // wait
9941
9942 if(((y>>(5))*TILES_PER_ROW + (x>>(5)) + first)!=t)
9943 {
9944 dclick_status=DCLICK_NOT;
9945 }
9946 else
9947 {
9948 if(type==0)
9949 {
9950 edit_tile(tile,flip,cs);
9951 draw_tile_list_window();
9952 redraw=true;
9953 }
9954 else
9955 {
9956 done=2;
9957 }
9958 }
9959 }
9960
9961 tile_clicked=t;
9962 }
9963 else if(x>300*mul && !bdown)
9964 {
9965 if(y<224*mul && first>0)
9966 {
9967 first-=TILES_PER_PAGE;
9968 redraw=true;
9969 }
9970
9971 if(y>=224*mul && first<TILES_PER_PAGE*(TILE_PAGES-1))
9972 {
9973 first+=TILES_PER_PAGE;
9974 redraw=true;
9975 }
9976
9977 bdown=true;
9978 }
9979
9980 if(type==1||type==2)
9981 {
9982 if(!bdown && isinRect(x,y,8*mul,216*mul+panel_yofs,23*mul,231*mul+panel_yofs))
9983 done=1;
9984
9985 if(!bdown && isinRect(x,y,148*mul,216*mul+panel_yofs,163*mul,231*mul+panel_yofs))
9986 done=2;
9987 }
9988 else if(!bdown && isinRect(x,y,127*mul,216*mul+panel_yofs,(127+15)*mul,(216+15)*mul+panel_yofs))
9989 {
9990 rect_sel=!rect_sel;
9991 copy=-1;
9992 redraw=true;
9993 }
9994 else if(!bdown && isinRect(x,y,150*mul,213*mul+panel_yofs,(150+28)*mul,(213+21)*mul+panel_yofs))
9995 {
9996 FONT *tf = font;
9997 font = tfont;
9998
9999 if(do_text_button(150*mul+screen_xofs,213*mul+screen_yofs+panel_yofs,28*mul,21*mul,"&Grab"))
10000 {
10001 font = tf;
10002 grab_tile(tile,cs);
10003 draw_tile_list_window();
10004 position_mouse_z(0);
10005 redraw=true;
10006 }
10007
10008 font = tf;
10009 }
10010 else if(!bdown && isinRect(x,y,(150+28)*mul,213*mul+panel_yofs,(150+28*2)*mul,(213+21)*mul+panel_yofs+21))
10011 {
10012 FONT *tf = font;
10013 font = tfont;
10014
10015 if(do_text_button((150+28)*mul+screen_xofs,213*mul+screen_yofs+panel_yofs,28*mul,21*mul,"&Edit"))
10016 {
10017 font = tf;
10018 edit_tile(tile,flip,cs);
10019 draw_tile_list_window();
10020 redraw=true;
10021 }
10022
10023 font = tf;
10024 }
10025 else if(!bdown && isinRect(x,y,(150+28*2)*mul,213*mul+panel_yofs,(150+28*3)*mul,(213+21)*mul+panel_yofs))
10026 {
10027 FONT *tf = font;
10028 font = tfont;
10029
10030 if(do_text_button((150+28*2)*mul+screen_xofs,213*mul+screen_yofs+panel_yofs,28*mul,21*mul,"Export"))
10031 {
10032 std::string initial_path = "tileset.png";
10033 if (strlen(datapath))
10034 initial_path = fmt::format("{}/{}", datapath, initial_path);
10035 if(prompt_for_new_file_compat("Export Tile Page (.png)","png",NULL,initial_path,true))
10036 {
10037 PALETTE temppal;
10038 get_palette(temppal);
10039 BITMAP *tempbmp=create_bitmap_ex(8,16*TILES_PER_ROW, 16*TILE_ROWS_PER_PAGE);
10040 draw_tiles(tempbmp,first,cs,false,true);
10041 save_bitmap(temppath, tempbmp, RAMpal);
10042 destroy_bitmap(tempbmp);
10043 }
10044 }
10045
10046 font = tf;
10047 }
10048 else if(!bdown && isinRect(x,y,(150+28*3)*mul,213*mul+panel_yofs,(150+28*4)*mul,(213+21)*mul+panel_yofs))
10049 {
10050 FONT *tf = font;
10051 font = tfont;
10052
10053 if(do_text_button((150+28*3)*mul+screen_xofs,213*mul+screen_yofs+panel_yofs,28*mul,21*mul,"Recolor"))
10054 {
10055 if(massRecolorSetup(cs))
10056 {
10057 go_tiles();
10058
10059 FOREACH_START(t)
10060 massRecolorApply(t);
10061 FOREACH_END
10062
10063 register_blank_tiles();
10064 }
10065 }
10066
10067 font = tf;
10068 }
10069 else if(!bdown && isinRect(x,y,(150+28*4)*mul,213*mul+panel_yofs,(150+28*5)*mul,(213+21)*mul+panel_yofs))
10070 {
10071 FONT *tf = font;
10072 font = tfont;
10073
10074 if(do_text_button((150+28*4)*mul+screen_xofs,213*mul+screen_yofs+panel_yofs,28*mul,21*mul,"Done"))
10075 {
10076 done=1;
10077 }
10078
10079 font = tf;
10080 }
10081
10082 bdown=true;
10083 }
10084
10085 bool r_click = false;
10086 bool force_draw_select = false;
10087 if(gui_mouse_b()&2 && !bdown && type==0)
10088 {
10089 int32_t x=(gui_mouse_x()-screen_xofs);//&0xFF0;
10090 int32_t y=(gui_mouse_y()-screen_yofs);//&0xF0;
10091
10092 if(y>=0 && y<208*mul)
10093 {
10094 x=zc_min(zc_max(x,0),(320*mul)-1);
10095 int32_t t = ((y)>>(5))*TILES_PER_ROW + ((x)>>(5)) + first;
10096
10097 if(t<zc_min(tile,tile2) || t>zc_max(tile,tile2))
10098 tile=tile2=t;
10099 }
10100
10101 bdown = r_click = true;
10102 force_draw_select = true;
10103 }
10104
10105 if(gui_mouse_b()==0)
10106 bdown=false;
10107
10108 position_mouse_z(0);
10109
10110 REDRAW:
10111
10112 if(!(framecnt%8) || force_draw_select || InvalidBG == 1)
10113 redraw=true;
10114 if(otl != tile || otl2 != tile2)
10115 {
10116 otl = tile;
10117 otl2 = tile2;
10118 redraw = true;
10119 }
10120
10121 if(redraw)
10122 {
10123 draw_tiles(first,cs);
10124 if(force_draw_select || (framecnt&8))
10125 {
10126 if(rect_sel)
10127 {
10128 for(int32_t i=zc_min(TILEROW(tile),TILEROW(tile2))*TILES_PER_ROW+
10129 zc_min(TILECOL(tile),TILECOL(tile2));
10130 i<=zc_max(TILEROW(tile),TILEROW(tile2))*TILES_PER_ROW+
10131 zc_max(TILECOL(tile),TILECOL(tile2)); i++)
10132 {
10133 if(i>=first && i<first+TILES_PER_PAGE &&
10134 TILECOL(i)>=zc_min(TILECOL(tile),TILECOL(tile2)) &&
10135 TILECOL(i)<=zc_max(TILECOL(tile),TILECOL(tile2)))
10136 {
10137 int32_t x=TILECOL(i)<<(5);
10138 int32_t y=TILEROW(i-first)<<(5);
10139 safe_rect(screen2,x,y,x+(16*mul)-1,y+(16*mul)-1,vc(TilePgCursorCol),2);
10140 }
10141 }
10142 }
10143 else
10144 {
10145 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); i++)
10146 {
10147 if(i>=first && i<first+TILES_PER_PAGE)
10148 {
10149 int32_t x=TILECOL(i)<<(5);
10150 int32_t y=TILEROW(i-first)<<(5);
10151 safe_rect(screen2,x,y,x+(16*mul)-1,y+(16*mul)-1,vc(TilePgCursorCol),2);
10152 }
10153 }
10154 }
10155 }
10156
10157 if(type==0)
10158 tile_info_0(tile,tile2,cs,copy,copycnt,first/TILES_PER_PAGE,rect_sel);
10159 else
10160 tile_info_1(otile,oflip,ocs,tile,flip,cs,copy,first/TILES_PER_PAGE, always_use_flip);
10161
10162 if(type==2)
10163 {
10164 char cbuf[16];
10165 sprintf(cbuf, "E&xtend: %s",ex==2 ? "32x32" : ex==1 ? "32x16" : "16x16");
10166 gui_textout_ln(screen, get_zc_font(font_lfont_l), (uint8_t *)cbuf, (235*mul)+screen_xofs, (212*mul)+screen_yofs+panel_yofs, jwin_pal[jcBOXFG],jwin_pal[jcBOX],0);
10167 }
10168 }
10169 anim_hw_screen();
10170
10171 if(r_click)
10172 {
10173 select_tile_view_menu.select_uid(MENUID_SELTILE_VIEW_HIDE_USED, HIDE_USED);
10174 select_tile_view_menu.select_uid(MENUID_SELTILE_VIEW_HIDE_UNUSED, HIDE_UNUSED);
10175 select_tile_view_menu.select_uid(MENUID_SELTILE_VIEW_HIDE_BLANK, HIDE_BLANK);
10176 select_tile_view_menu.select_uid(MENUID_SELTILE_VIEW_HIDE_8BIT, HIDE_8BIT_MARKER);
10177
10178 int current_tile_format = MENUID_SELTILE_COLOR_DEPTH_4_BIT;
10179 if (newtilebuf[tile].format == tf8Bit)
10180 current_tile_format = MENUID_SELTILE_COLOR_DEPTH_8_BIT;
10181 select_tile_color_depth_menu.select_only_uid(current_tile_format);
10182 select_tile_color_depth_cb = [&](int format){
10183 if (newtilebuf[tile].format == format)
10184 return;
10185
10186 bool skip_prompt = true;
10187 do_convert_tile(tile, tile2, cs, rect_sel, format, false, false, skip_prompt);
10188 };
10189
10190 NewMenu rcmenu
10191 {
10192 { "Copy", [&]()
10193 {
10194 copy = zc_min(tile,tile2);
10195 copycnt = abs(tile-tile2)+1;
10196 } },
10197 { "Paste", [&]()
10198 {
10199 bool b = copy_tiles(tile, tile2, copy, copycnt, rect_sel, false);
10200 if (!b) mark_save_dirty();
10201 }, nullopt, copy < 0 ? MFL_DIS : 0 },
10202 { "Move", [&]()
10203 {
10204 bool b = copy_tiles(tile, tile2, copy, copycnt, rect_sel, true);
10205 if (!b) mark_save_dirty();
10206 }, nullopt, copy < 0 ? MFL_DIS : 0 },
10207 { "Clear", [&]()
10208 {
10209 delete_tiles(tile, tile2, rect_sel);
10210 } },
10211 { "Set as Reference", [&]()
10212 {
10213 reftile = tile;
10214 } },
10215 {},
10216 { "Edit", [&]()
10217 {
10218 edit_tile(tile, flip, cs);
10219 draw_tile_list_window();
10220 } },
10221 { "Grab", [&]()
10222 {
10223 grab_tile(tile, cs);
10224 draw_tile_list_window();
10225 position_mouse_z(0);
10226 } },
10227 { "Scale", [&]()
10228 {
10229 bool b = scale_or_rotate_tiles(tile, tile2, cs, false);
10230 if (!b) mark_save_dirty();
10231 }, nullopt, type != 0 ? MFL_DIS : 0 },
10232 { "Angular Rotation", [&]()
10233 {
10234 bool b = scale_or_rotate_tiles(tile, tile2, cs, true);
10235 if (!b) mark_save_dirty();
10236 }, nullopt, type != 0 ? MFL_DIS : 0 },
10237 { "Color Depth", &select_tile_color_depth_menu },
10238 {},
10239 { "Blank?", [&]()
10240 {
10241 show_blank_tile(tile);
10242 } },
10243 {},
10244 { "View ", &select_tile_view_menu },
10245 { "Overlay", [&]()
10246 {
10247 overlay_tile(newtilebuf, tile, copy, cs, 0);
10248 } },
10249 { "H-Flip", [&]()
10250 {
10251 flip ^= 1;
10252 go_tiles();
10253
10254 if(type == 0)
10255 {
10256 normalize(tile, tile2, rect_sel, flip);
10257 flip = 0;
10258 }
10259 } },
10260 { "V-Flip", [&]()
10261 {
10262 flip ^= 2;
10263 go_tiles();
10264
10265 if(type == 0)
10266 {
10267 normalize(tile, tile2, rect_sel, flip);
10268 flip = 0;
10269 }
10270 } },
10271 { "Create Combos", [&]()
10272 {
10273 if(rect_sel)
10274 make_combos_rect(top, left, rows, columns, cs);
10275 else
10276 make_combos(zc_min(tile, tile2), zc_max(tile, tile2), cs);
10277 }, nullopt, type != 0 ? MFL_DIS : 0 },
10278 { "Insert", [&]()
10279 {
10280 bool warn = (rect_sel
10281 && ((tile/20)!=(tile2/20))
10282 && !(tile%20==0&&tile2%20==19));
10283 int32_t z = zc_min(tile, tile2);
10284 int32_t count = abs(tile-tile2) + 1;
10285 tile = z;
10286 tile2 = NEWMAXTILES;
10287 copy = tile + count;
10288 copycnt = NEWMAXTILES-copy;
10289
10290 string msg;
10291
10292 if(count>1)
10293 msg = fmt::format("Insert {} blank tiles?",count);
10294 else
10295 msg = "Insert a blank tile?";
10296
10297 AlertDialog("Insert Tiles", msg
10298 +"\nThis will offset the tiles that follow!"
10299 +(warn?"\nInserting tiles ignores rectangular selections!":""),
10300 [&](bool ret,bool)
10301 {
10302 if(ret)
10303 {
10304 go_tiles();
10305 if(copy_tiles(copy, tile2, tile, copycnt, false, true))
10306 mark_save_dirty();
10307 }
10308 }).show();
10309
10310 copy=-1;
10311 tile2=tile=z;
10312 }, nullopt, type != 0 ? MFL_DIS : 0 },
10313 { "Remove", [&]()
10314 {
10315 bool warn = (rect_sel
10316 && ((tile/20)!=(tile2/20))
10317 && !(tile%20==0&&tile2%20==19));
10318 int32_t z = zc_min(tile, tile2);
10319 int32_t count = abs(tile-tile2) + 1;
10320 tile = z;
10321 tile2 = NEWMAXTILES;
10322 copy = tile + count;
10323 copycnt = NEWMAXTILES-copy;
10324
10325 string msg;
10326
10327 if(count>1)
10328 msg = fmt::format("Remove tiles {} - {}?", tile, copy-1);
10329 else
10330 msg = fmt::format("Remove tile {}?", tile);
10331
10332 AlertDialog("Remove Tiles", msg
10333 +"\nThis will offset the tiles that follow!"
10334 +(warn?"\nRemoving tiles ignores rectangular selections!":""),
10335 [&](bool ret,bool)
10336 {
10337 if(ret)
10338 {
10339 go_tiles();
10340 if(copy_tiles(tile, tile2, copy, copycnt, false, true))
10341 mark_save_dirty();
10342 }
10343 }).show();
10344
10345 copy=-1;
10346 tile2=tile=z;
10347 }, nullopt, type != 0 ? MFL_DIS : 0 },
10348 };
10349 rcmenu.pop(window_mouse_x(),window_mouse_y());
10350 redraw = true;
10351 r_click = false;
10352 goto REDRAW;
10353 }
10354 }
10355 while(!done);
10356
10357 while(gui_mouse_b()) ; // wait
10358
10359 register_blank_tiles();
10360 register_used_tiles();
10361 setup_combo_animations();
10362 setup_combo_animations2();
10363 int32_t ret = done-1;
10364 if(ret)
10365 {
10366 _selected_tile = tile;
10367 _selected_tcset = cs;
10368 }
10369
10370 popup_zqdialog_end();
10371 return ret;
10372 }
10373 int32_t select_tile_2(int32_t &tile,int32_t &flip,int32_t type,int32_t &cs,bool edit_cs,int32_t exnow, bool always_use_flip)
10374 {
10375 if(_selected_tile > -1)
10376 {
10377 tile = _selected_tile;
10378 cs = _selected_tcset;
10379 }
10380 int32_t ret = select_tile(tile,flip,type,cs,edit_cs,exnow,always_use_flip);
10381 if(_selected_tile < 0)
10382 {
10383 _selected_tile = tile;
10384 _selected_tcset = cs;
10385 }
10386 return ret;
10387 }
10388
10389 int32_t onTiles()
10390 {
10391 return onGotoTiles(-1);
10392 }
10393
10394 int32_t onGotoTiles(int32_t startfrom)
10395 {
10396 static int32_t t = 0;
10397 if (startfrom > -1)
10398 t = startfrom;
10399 int32_t flip = 0;
10400 int32_t c = CSet;
10401 reset_pal_cycling();
10402 rebuild_trans_table();
10403 select_tile(t, flip, 0, c, true);
10404 refresh(rALL);
10405 return D_O_K;
10406 }
10407
10408 int32_t combopage_animate = 1;
10409 void draw_combo(BITMAP *dest, int x,int y,int c,int cs,bool animate)
10410 {
10411 if(unsigned(c)<MAXCOMBOS)
10412 {
10413 newcombo& cmb = combobuf[c];
10414 int t = cmb.tile;
10415 if(!animate)
10416 cmb.tile = cmb.o_tile;
10417 put_combo(dest,x,y,c,cs,0,0);
10418 cmb.tile = t;
10419 }
10420 else
10421 {
10422 rectfill(dest,x,y,x+32-1,y+32-1,0);
10423 }
10424 }
10425
10426 void draw_combos(int32_t page,int32_t cs,bool cols)
10427 {
10428 clear_bitmap(screen2);
10429 BITMAP *buf = create_bitmap_ex(8,16,16);
10430
10431 int32_t w = 32;
10432 int32_t h = 32;
10433 int32_t mul = 2;
10434
10435 int32_t window_xofs=(zq_screen_w-640-12)>>1;
10436 int32_t window_yofs=(zq_screen_h-480-25-6)>>1;
10437 int32_t screen_xofs=window_xofs+6;
10438 int32_t screen_yofs=window_yofs+25;
10439
10440 if(cols==false)
10441 {
10442 for(int32_t i=0; i<256; i++) // 13 rows, leaving 32 pixels from y=208 to y=239
10443 {
10444 int32_t x = (i%COMBOS_PER_ROW)*w;
10445 int32_t y = (i/COMBOS_PER_ROW)*h;
10446
10447 combotile_override_x = x+screen_xofs+(w-16)/2;
10448 combotile_override_y = y+screen_yofs+(h-16)/2;
10449 draw_combo(buf,0,0,i+(page<<8),cs,combopage_animate);
10450 stretch_blit(buf,screen2,0,0,16,16,x,y,w,h);
10451 }
10452 }
10453 else
10454 {
10455 int32_t c = 0;
10456
10457 for(int32_t i=0; i<256; i++)
10458 {
10459 int32_t x = (i%COMBOS_PER_ROW)*w;
10460 int32_t y = (i/COMBOS_PER_ROW)*h;
10461
10462 combotile_override_x = x+screen_xofs+(w-16)/2;
10463 combotile_override_y = y+screen_yofs+(h-16)/2;
10464 draw_combo(buf,0,0,c+(page<<8),cs,combopage_animate);
10465 stretch_blit(buf,screen2,0,0,16,16,x,y,w,h);
10466 ++c;
10467
10468 if((i&3)==3)
10469 c+=48;
10470
10471 if((i%COMBOS_PER_ROW)==(COMBOS_PER_ROW-1))
10472 c-=256;
10473 }
10474 }
10475 combotile_override_x = combotile_override_y = -1;
10476
10477 for(int32_t x=(64*mul); x<(320*mul); x+=(64*mul))
10478 {
10479 vline(screen2,x,0,(208*mul)-1,vc(15));
10480 }
10481
10482 destroy_bitmap(buf);
10483 }
10484
10485 void combo_info(int32_t tile,int32_t tile2,int32_t cs,int32_t copy,int32_t copycnt,int32_t page,int32_t buttons)
10486 {
10487 int32_t yofs=3;
10488 static BITMAP *buf = create_bitmap_ex(8,16,16);
10489 int32_t mul = 2;
10490 FONT *tfont = get_zc_font(font_lfont_l);
10491
10492 rectfill(screen2,0,210*2,(320*2)-1,(240*2)-1,jwin_pal[jcBOX]);
10493 hline(screen2, 0, (210*2)-2, (320*2)-1, jwin_pal[jcMEDLT]);
10494 hline(screen2, 0, (210*2)-1, (320*2)-1, jwin_pal[jcLIGHT]);
10495
10496 jwin_draw_frame(screen2,(31*mul)-2,((216*mul)+yofs)-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
10497
10498 if(copy>=0)
10499 {
10500 put_combo(buf,0,0,copy,cs,0,0);
10501 stretch_blit(buf,screen2,0,0,16,16,31*mul,216*mul+yofs,16*mul,16*mul);
10502
10503 if(copycnt>1)
10504 {
10505 textprintf_right_ex(screen2,tfont,28*mul,(216*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d-",copy);
10506 textprintf_right_ex(screen2,tfont,24*mul,(224*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",copy+copycnt-1);
10507 }
10508 else
10509 {
10510 textprintf_right_ex(screen2,tfont,24*mul,(220*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",copy);
10511 }
10512 }
10513 else
10514 {
10515 if (InvalidBG == 2)
10516 {
10517 draw_checkerboard(screen2, 31 * mul, 216 * mul + yofs, 16 * mul);
10518 }
10519 else if(InvalidBG == 1)
10520 {
10521 draw_static(screen2, 31*mul, 216*mul+yofs, 16*mul, 16*mul);
10522 }
10523 else
10524 {
10525 rectfill(screen2, (31*mul), (216*mul)+yofs, (31*mul)+31, (216*mul)+yofs+31, vc(0));
10526 rect(screen2, (31*mul), (216*mul)+yofs, (31*mul)+31, (216*mul)+yofs+31, vc(15));
10527 line(screen2, (31*mul), (216*mul)+yofs, (31*mul)+31, (216*mul)+yofs+31, vc(15));
10528 line(screen2, (31*mul), (216*mul)+yofs+31, (31*mul)+31, (216*mul)+yofs, vc(15));
10529 }
10530 }
10531
10532 jwin_draw_frame(screen2,(53*mul)-2,(216*mul)+yofs-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
10533 put_combo(buf,0,0,tile,cs,0,0);
10534 stretch_blit(buf,screen2,0,0,16,16,53*mul,216*mul+yofs,16*mul,16*mul);
10535
10536 if(tile>tile2)
10537 {
10538 zc_swap(tile,tile2);
10539 }
10540
10541 char cbuf[8];
10542 cbuf[0]=0;
10543
10544 if(tile2!=tile)
10545 {
10546 sprintf(cbuf,"-%d",tile2);
10547 }
10548
10549 textprintf_ex(screen2,tfont,(73*mul),(216*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"combo: CSet %d", cs);
10550 textprintf_ex(screen2,tfont,(73*mul),(224*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d%s",tile,cbuf);
10551
10552 if(tile2==tile)
10553 {
10554 int32_t nextcombo=combobuf[tile].nextcombo;
10555 int32_t nextcset=(combobuf[tile].animflags & AF_CYCLENOCSET) ? cs : combobuf[tile].nextcset;
10556 jwin_draw_frame(screen2,(136*mul)-2,(216*mul)+yofs-2,(16*mul)+4,(16*mul)+4,FR_DEEP);
10557
10558 if(nextcombo>0 && !(combobuf[tile].animflags & AF_CYCLEUNDERCOMBO))
10559 {
10560 put_combo(buf,0,0,nextcombo,nextcset,0,0);
10561 stretch_blit(buf,screen2,0,0,16,16,136*mul,216*mul+yofs,16*mul,16*mul);
10562 }
10563 else
10564 {
10565 if (InvalidBG == 2)
10566 {
10567 draw_checkerboard(screen2, 136 * mul, 216 * mul + yofs, 16 * mul);
10568 }
10569 else if(InvalidBG == 1)
10570 {
10571 draw_static(screen2, 136*mul, 216*mul+yofs, 16*mul, 16*mul);
10572 }
10573 else
10574 {
10575 rectfill(screen2, (136*mul), (216*mul)+yofs, (136*mul)+31, (216*mul)+yofs+31, vc(0));
10576 rect(screen2, (136*mul), (216*mul)+yofs, (136*mul)+31, (216*mul)+yofs+31, vc(15));
10577 line(screen2, (136*mul), (216*mul)+yofs, (136*mul)+31, (216*mul)+yofs+31, vc(15));
10578 line(screen2, (136*mul), (216*mul)+yofs+31, (136*mul)+31, (216*mul)+yofs, vc(15));
10579 }
10580 }
10581
10582 textprintf_right_ex(screen2,tfont,(132*mul),(216*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"Cycle:");
10583 textprintf_right_ex(screen2,tfont,(132*mul),(224*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",nextcombo);
10584 }
10585
10586
10587 FONT *tf = font;
10588 font = tfont;
10589
10590 draw_checkbox(screen2,320,440+yofs,16,combopage_animate);
10591 textprintf_ex(screen2,tfont,320+18,440+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"Animate");
10592
10593 if(buttons&2)
10594 {
10595 draw_text_button(screen2,404,426+yofs,88,42,"Edit",jwin_pal[jcBOXFG],jwin_pal[jcBOX],0,true);
10596 }
10597
10598 if(buttons&4)
10599 {
10600 draw_text_button(screen2,494,426+yofs,88,42,"Done",jwin_pal[jcBOXFG],jwin_pal[jcBOX],0,true);
10601 }
10602
10603 font = tf;
10604
10605 jwin_draw_icon(screen2,(305*mul+4),220*mul-6+yofs,jwin_pal[jcBOXFG],BTNICON_ARROW_UP,6,true);
10606 textprintf_ex(screen2,tfont,(293*mul),(220*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"p:");
10607 textprintf_centre_ex(screen2,tfont,(309*mul),(220*mul)+yofs,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",page);
10608 jwin_draw_icon(screen2,(305*mul+4),228*mul+3+yofs,jwin_pal[jcBOXFG],BTNICON_ARROW_DOWN,6,true);
10609
10610 int32_t w = 640;
10611 int32_t h = 480;
10612 int32_t window_xofs=(zq_screen_w-w-12)>>1;
10613 int32_t window_yofs=(zq_screen_h-h-25-6)>>1;
10614 int32_t screen_xofs=window_xofs+6;
10615 int32_t screen_yofs=window_yofs+25;
10616
10617 blit(screen2,screen,0,0,screen_xofs,screen_yofs,w,h);
10618 }
10619
10620 void sel_combo(int32_t &tile, int32_t &tile2, int32_t s, bool cols)
10621 {
10622 int32_t page = tile&0xFF00;
10623 tile &= 0xFF;
10624
10625 if(!cols)
10626 tile += s;
10627 else
10628 {
10629 if(s==-COMBOS_PER_ROW)
10630 tile-=4;
10631
10632 if(s==COMBOS_PER_ROW)
10633 tile+=4;
10634
10635 if(s==-1)
10636 tile-=1;
10637
10638 if(s==1)
10639 tile+=1;
10640 }
10641
10642 /*
10643 if(s==1)
10644 {
10645 if((tile&3)==3)
10646 tile+=48;
10647 else
10648 ++tile;
10649 }
10650 if(s==-1)
10651 {
10652 if((tile&3)==0)
10653 tile-=48;
10654 else
10655 --tile;
10656 }
10657 }
10658 */
10659 bound(tile,0,255);
10660 tile += page;
10661
10662 if(!(key[KEY_LSHIFT] || key[KEY_RSHIFT]))
10663 tile2 = tile;
10664 }
10665
10666 void draw_combo_list_window()
10667 {
10668 int32_t window_xofs=0;
10669 int32_t window_yofs=0;
10670 int32_t w = 640;
10671 int32_t h = 480;
10672
10673 window_xofs=(zq_screen_w-w-12)>>1;
10674 window_yofs=(zq_screen_h-h-25-6)>>1;
10675 jwin_draw_win(screen, window_xofs, window_yofs, w+6+6, h+25+6, FR_WIN);
10676 jwin_draw_frame(screen, window_xofs+4, window_yofs+23, w+2+2, h+4+2-64, FR_DEEP);
10677 FONT *oldfont = font;
10678 font = get_zc_font(font_lfont);
10679 jwin_draw_titlebar(screen, window_xofs+3, window_yofs+3, w+6, 18, "Select Combo", true);
10680 font=oldfont;
10681 }
10682
10683
10684 static int32_t _selected_combo=-1, _selected_cset=-1;
10685 bool select_combo_2(int32_t &cmb,int32_t &cs)
10686 {
10687 popup_zqdialog_start();
10688 reset_combo_animations();
10689 reset_combo_animations2();
10690 combopage_animate = zc_get_config("ZQ_GUI","combopage_animate",1);
10691 // static int32_t cmb=0;
10692 int32_t page=cmb>>8;
10693 int32_t tile2=cmb;
10694 int32_t done=0;
10695 int32_t tile_clicked=-1;
10696 int32_t t2;
10697 int32_t copy=-1;
10698 int32_t copycnt=0;
10699
10700 position_mouse_z(0);
10701
10702 int32_t w = 640;
10703 int32_t h = 480;
10704 int32_t window_xofs=(zq_screen_w-w-12)>>1;
10705 int32_t window_yofs=(zq_screen_h-h-25-6)>>1;
10706 int32_t screen_xofs=window_xofs+6;
10707 int32_t screen_yofs=window_yofs+25;
10708 int32_t panel_yofs=3;
10709 int32_t mul = 2;
10710 FONT *tfont = get_zc_font(font_lfont_l);
10711
10712 draw_combo_list_window();
10713 draw_combos(page,cs,true);
10714 combo_info(cmb,tile2,cs,copy,copycnt,page,4);
10715 anim_hw_screen();
10716
10717 while(gui_mouse_b()) ; // wait
10718
10719 bool bdown=false;
10720 int otl = cmb, otl2 = tile2;
10721
10722 do
10723 {
10724 HANDLE_CLOSE_ZQDLG();
10725 if(exiting_program) break;
10726 //rest(4);
10727
10728 if(mouse_z<0)
10729 {
10730 if(page<COMBO_PAGES-1)
10731 {
10732 ++page;
10733 cmb=tile2=(page<<8)+(cmb&0xFF);
10734 }
10735
10736 position_mouse_z(0);
10737 }
10738 else if(mouse_z>0)
10739 {
10740 if(page>0)
10741 {
10742 --page;
10743 cmb=tile2=(page<<8)+(cmb&0xFF);
10744 }
10745
10746 position_mouse_z(0);
10747 }
10748
10749 if(keypressed())
10750 {
10751 switch(readkey()>>8)
10752 {
10753 case KEY_DEL:
10754 cmb=0;
10755 done=2;
10756 break;
10757
10758 case KEY_ENTER_PAD:
10759 case KEY_ENTER:
10760 done=2;
10761 break;
10762
10763 case KEY_ESC:
10764 done=1;
10765 break;
10766
10767 case KEY_F1:
10768 onHelp();
10769 break;
10770
10771 case KEY_EQUALS:
10772 case KEY_PLUS_PAD:
10773 cs = (cs<13) ? cs+1:0;
10774 break;
10775
10776 case KEY_MINUS:
10777 case KEY_MINUS_PAD:
10778 cs = (cs>0) ? cs-1:13;
10779 break;
10780
10781 case KEY_UP:
10782 sel_combo(cmb,tile2,-COMBOS_PER_ROW,true);
10783 break;
10784
10785 case KEY_DOWN:
10786 sel_combo(cmb,tile2,COMBOS_PER_ROW,true);
10787 break;
10788
10789 case KEY_LEFT:
10790 sel_combo(cmb,tile2,-1,true);
10791 break;
10792
10793 case KEY_RIGHT:
10794 sel_combo(cmb,tile2,1,true);
10795 break;
10796
10797 case KEY_PGUP:
10798 if(page>0)
10799 {
10800 --page;
10801 cmb=tile2=(page<<8)+(cmb&0xFF);
10802 }
10803 break;
10804
10805 case KEY_PGDN:
10806 if(page<COMBO_PAGES-1)
10807 {
10808 ++page;
10809 cmb=tile2=(page<<8)+(cmb&0xFF);
10810 }
10811 break;
10812
10813 case KEY_P:
10814 {
10815 int32_t choosepage=getnumber("Goto Page", (PreFillComboEditorPage?page:0));
10816
10817 if(!cancelgetnum)
10818 page=(zc_min(choosepage,COMBO_PAGES-1));
10819
10820 cmb=tile2=(page<<8)+(cmb&0xFF);
10821 break;
10822 }
10823 }
10824
10825 clear_keybuf();
10826 }
10827
10828 if(gui_mouse_b()&1)
10829 {
10830 if(isinRect(gui_mouse_x(),gui_mouse_y(),window_xofs + w + 12 - 21, window_yofs + 5, window_xofs + w +12 - 21 + 15, window_yofs + 5 + 13))
10831 {
10832 if(do_x_button(screen, w+12+window_xofs - 21, 5+window_yofs))
10833 {
10834 done=1;
10835 }
10836 }
10837
10838 int32_t x=gui_mouse_x()-screen_xofs;
10839 int32_t y=gui_mouse_y()-screen_yofs;
10840
10841 if(y>=0 && y<208*mul)
10842 {
10843 x=zc_min(zc_max(x,0),(320*mul)-1);
10844 int32_t t;
10845
10846 t = ((x>>7)*52) + ((x>>5)&3) + ((y>>5)<<2);
10847
10848 bound(t,0,255);
10849 t+=page<<8;
10850 cmb=tile2=t;
10851
10852 if(tile_clicked!=t)
10853 {
10854 dclick_status=DCLICK_NOT;
10855 }
10856 else if(dclick_status == DCLICK_AGAIN)
10857 {
10858 while(gui_mouse_b()) ; // wait
10859
10860 t2 = ((x>>7)*52) + ((x>>5)&3) + ((y>>5)<<2);
10861
10862 if(t2!=t)
10863 {
10864 dclick_status=DCLICK_NOT;
10865 }
10866 else
10867 {
10868 done=2;
10869 }
10870 }
10871
10872 tile_clicked=t;
10873 }
10874 else if(y>=(208*mul) && x>(300*mul) && !bdown)
10875 {
10876 if(y<(224*mul)+panel_yofs && page>0)
10877 {
10878 --page;
10879 }
10880
10881 if(y>=(224*mul)+panel_yofs && page<COMBO_PAGES-1)
10882 {
10883 ++page;
10884 }
10885
10886 bdown=true;
10887 }
10888
10889 if(!bdown && isinRect(x,y,(247*mul),(213*mul),((247+44)*mul),((213+21)*mul)))
10890 {
10891 FONT *tf = font;
10892 font = tfont;
10893
10894 if(do_text_button((247*mul)+screen_xofs,(213*mul)+screen_yofs+panel_yofs,(44*mul),(21*mul),"Done"))
10895 {
10896 done=2;
10897 }
10898
10899 font = tf;
10900 }
10901 else if(!bdown && isinRect(x,y,320,440+panel_yofs,320+16,440+panel_yofs+16))
10902 {
10903 FONT *tf = font;
10904 font = tfont;
10905
10906 //do_scheckbox(screen2,320,440+panel_yofs,16,jwin_pal[jcTEXTBG],jwin_pal[jcTEXTFG],combopage_animate,screen_xofs,screen_yofs);
10907 combopage_animate = combopage_animate ? 0 : 1;
10908 zc_set_config("ZQ_GUI","combopage_animate",combopage_animate);
10909
10910 font = tf;
10911 }
10912
10913 bdown=true;
10914 }
10915
10916 bool r_click = false;
10917
10918 bool force_draw_select = false;
10919 if(gui_mouse_b()&2 && !bdown)
10920 {
10921 int32_t x=gui_mouse_x()+screen_xofs;
10922 int32_t y=gui_mouse_y()+screen_yofs;
10923
10924 if(y>=0 && y<208*mul)
10925 {
10926 x=zc_min(zc_max(x,0),(320*mul)-1);
10927 int32_t t;
10928
10929 t = ((x>>7)*52) + ((x>>5)&3) + ((y>>5)<<2);
10930
10931 bound(t,0,255);
10932 t+=page<<8;
10933
10934 if(t<zc_min(cmb,tile2) || t>zc_max(cmb,tile2))
10935 cmb=tile2=t;
10936 }
10937
10938 bdown = r_click = true;
10939 force_draw_select = true;
10940 }
10941
10942 if(gui_mouse_b()==0)
10943 bdown=false;
10944
10945 if(otl != cmb || otl2 != tile2)
10946 {
10947 otl = cmb;
10948 otl2 = tile2;
10949 }
10950
10951 // if(true) // redraw every frame now. Eyeball combos need to animate regardless, and cursor blinks every 8 frames anyway.
10952 {
10953 draw_combos(page,cs,true);
10954 combo_info(cmb,tile2,cs,copy,copycnt,page,4);
10955 if(force_draw_select || (framecnt&8))
10956 {
10957 int32_t x,y;
10958
10959 for(int32_t i=zc_min(cmb,tile2); i<=zc_max(cmb,tile2); i++)
10960 {
10961 if((i>>8)==page)
10962 {
10963 int32_t t=i&255;
10964
10965 x=((t&3) + ((t/52)<<2)) << 5;
10966 y=((t%52)>>2) << 5;
10967
10968 safe_rect(screen,x+screen_xofs,y+screen_yofs,x+screen_xofs+(16*mul)-1,y+screen_yofs+(16*mul)-1,vc(CmbPgCursorCol),2);
10969 }
10970 }
10971 }
10972 }
10973 anim_hw_screen();
10974 }
10975 while(!done);
10976
10977 while(gui_mouse_b()) ; // wait
10978
10979 setup_combo_animations();
10980 setup_combo_animations2();
10981
10982 bool ret = done==2;
10983 if(ret)
10984 {
10985 _selected_combo = cmb;
10986 _selected_cset = cs;
10987 }
10988
10989 popup_zqdialog_end();
10990 return ret;
10991 }
10992
10993 bool select_combo_3(int32_t &cmb,int32_t &cs)
10994 {
10995 if(_selected_combo < 0)
10996 {
10997 _selected_combo = Combo;
10998 _selected_cset = CSet;
10999 }
11000 cmb = _selected_combo;
11001 cs = _selected_cset;
11002 return select_combo_2(cmb,cs);
11003 }
11004
11005 bool advpaste(int32_t tile, int32_t tile2, int32_t copy)
11006 {
11007 static bitstring pasteflags;
11008 static const vector<CheckListInfo> advp_names =
11009 {
11010 { "Tile" },
11011 { "CSet2" },
11012 { "Solidity" },
11013 { "Animation" },
11014 { "Type" },
11015 { "Inherent Flag" },
11016 { "Attributes", "Including Attribytes and Attrishorts" },
11017 { "Flags", "The 16 Flags on the 'Flags' tab" },
11018 { "Gen. Flags", "The 2 'General Flags' on the 'Flags' tab" },
11019 { "Label" },
11020 { "Script" },
11021 { "Effect" },
11022 { "Triggers Tab" },
11023 { "Lifting Tab" },
11024 { "Gen: Movespeed", "The Movespeed related values from the 'General' tab" },
11025 { "Gen: SFX", "The SFX related values from the 'General' tab" },
11026 { "Gen: Sprites", "The Sprites related values from the 'General' tab" },
11027 { "Gen: Z Height", "The combo's 'Z Height'/'Z Step Height' settings, and related flags" },
11028 { "Misc Weapon Data", "The combo's 'Misc Weapon Data' settings" },
11029 // should be CMB_ADVP_SZ long
11030 };
11031
11032 if(!call_checklist_dialog("Advanced Paste",advp_names,pasteflags))
11033 return false;
11034
11035 //Paste to each combo in the range
11036 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); ++i)
11037 combobuf[i].advpaste(combobuf[copy], pasteflags);
11038
11039 if(pasteflags.get(CMB_ADVP_TILE)) //reset animations if needed
11040 {
11041 setup_combo_animations();
11042 setup_combo_animations2();
11043 }
11044
11045 return true;
11046 }
11047
11048 int32_t combo_screen(int32_t pg, int32_t tl)
11049 {
11050 popup_zqdialog_start();
11051 reset_combo_animations();
11052 reset_combo_animations2();
11053 combopage_animate = zc_get_config("ZQ_GUI","combopage_animate",1);
11054 static int32_t tile=0;
11055 static int32_t page=0;
11056
11057 if(pg>-1)
11058 page = pg;
11059
11060 if(tl>-1)
11061 tile = tl;
11062
11063 int32_t tile2=tile;
11064 int32_t done=0;
11065 int32_t cs = CSet;
11066 int32_t copy=-1;
11067 int32_t copycnt=0;
11068
11069 int32_t tile_clicked=-1;
11070 int32_t t2;
11071
11072 bool masscopy;
11073
11074 int32_t w = 640;
11075 int32_t h = 480;
11076 int32_t window_xofs=(zq_screen_w-w-12)>>1;
11077 int32_t window_yofs=(zq_screen_h-h-25-6)>>1;
11078 int32_t screen_xofs=window_xofs+6;
11079 int32_t screen_yofs=window_yofs+25;
11080 int32_t panel_yofs=3;
11081 int32_t mul = 2;
11082 FONT *tfont = get_zc_font(font_lfont_l);
11083
11084 draw_combo_list_window();
11085 draw_combos(page,cs,true);
11086 combo_info(tile,tile2,cs,copy,copycnt,page,6);
11087 anim_hw_screen();
11088 go_combos();
11089 position_mouse_z(0);
11090
11091 while(gui_mouse_b()) ; // wait
11092
11093 bool bdown=false;
11094 int otl = tile, otl2 = tile2;
11095
11096 do
11097 {
11098 HANDLE_CLOSE_ZQDLG();
11099 if(exiting_program) break;
11100 //rest(4);
11101
11102 if(mouse_z<0)
11103 {
11104 if(page<COMBO_PAGES-1)
11105 {
11106 ++page;
11107 tile=tile2=(page<<8)+(tile&0xFF);
11108 }
11109
11110 position_mouse_z(0);
11111 }
11112 else if(mouse_z>0)
11113 {
11114 if(page>0)
11115 {
11116 --page;
11117 tile=tile2=(page<<8)+(tile&0xFF);
11118 }
11119
11120 position_mouse_z(0);
11121 }
11122
11123 if(keypressed())
11124 {
11125 switch(readkey()>>8)
11126 {
11127 case KEY_ENTER_PAD:
11128 case KEY_ENTER:
11129 done=2;
11130 break;
11131
11132 case KEY_ESC:
11133 done=1;
11134 break;
11135
11136 case KEY_F1:
11137 onHelp();
11138 break;
11139
11140 case KEY_EQUALS:
11141 case KEY_PLUS_PAD:
11142 if(CHECK_CTRL_CMD)
11143 {
11144 int32_t amnt = (key[KEY_LSHIFT] || key[KEY_RSHIFT]) ?
11145 ((key[KEY_ALT] || key[KEY_ALTGR]) ? TILES_PER_PAGE*10 : TILES_PER_ROW)
11146 : ((key[KEY_ALT] || key[KEY_ALTGR]) ? TILES_PER_PAGE : 1);
11147
11148 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); ++i)
11149 {
11150 combobuf[i].set_tile(wrap(combobuf[i].o_tile + amnt,
11151 0, NEWMAXTILES-1));
11152 }
11153
11154 setup_combo_animations();
11155 }
11156 else
11157 {
11158 cs = (cs<13) ? cs+1:0;
11159 }
11160
11161 break;
11162
11163 case KEY_MINUS:
11164 case KEY_MINUS_PAD:
11165 if(CHECK_CTRL_CMD)
11166 {
11167 int32_t amnt = (key[KEY_LSHIFT] || key[KEY_RSHIFT]) ?
11168 ((key[KEY_ALT] || key[KEY_ALTGR]) ? TILES_PER_PAGE*10 : TILES_PER_ROW)
11169 : ((key[KEY_ALT] || key[KEY_ALTGR]) ? TILES_PER_PAGE : 1);
11170
11171 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); ++i)
11172 {
11173 combobuf[i].set_tile(wrap(combobuf[i].o_tile - amnt,
11174 0, NEWMAXTILES-1));
11175 }
11176
11177 setup_combo_animations();
11178 }
11179 else
11180 {
11181 cs = (cs>0) ? cs-1:13;
11182 }
11183
11184 break;
11185
11186 case KEY_UP:
11187 sel_combo(tile,tile2,-COMBOS_PER_ROW,true);
11188 break;
11189
11190 case KEY_DOWN:
11191 sel_combo(tile,tile2,COMBOS_PER_ROW,true);
11192 break;
11193
11194 case KEY_LEFT:
11195 sel_combo(tile,tile2,-1,true);
11196 break;
11197
11198 case KEY_RIGHT:
11199 sel_combo(tile,tile2,1,true);
11200 break;
11201
11202 case KEY_PGUP:
11203 if(page>0)
11204 {
11205 --page;
11206 tile=tile2=(page<<8)+(tile&0xFF);
11207 }
11208 break;
11209
11210 case KEY_PGDN:
11211 if(page<COMBO_PAGES-1)
11212 {
11213 ++page;
11214 tile=tile2=(page<<8)+(tile&0xFF);
11215 }
11216 break;
11217
11218 case KEY_A:
11219 {
11220 tile=(page<<8);
11221 tile2=(page<<8)+(0xFF);
11222 }
11223 break;
11224
11225 case KEY_P:
11226 {
11227 int32_t choosepage = getnumber("Goto Page", (PreFillComboEditorPage?page:0));
11228
11229 if(!cancelgetnum)
11230 page=(zc_min(choosepage,COMBO_PAGES-1));
11231
11232 tile=tile2=(page<<8)+(tile&0xFF);
11233 }
11234 break;
11235
11236 case KEY_U:
11237 comeback_combos();
11238 break;
11239
11240 case KEY_E:
11241 go_combos();
11242 edit_combo(tile,false,cs);
11243 setup_combo_animations();
11244 setup_combo_animations2();
11245 break;
11246
11247 case KEY_C:
11248 go_combos();
11249 copy=zc_min(tile,tile2);
11250 copycnt=abs(tile-tile2)+1;
11251 break;
11252
11253 case KEY_H:
11254 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); i++)
11255 {
11256 combobuf[i].flip^=1;
11257 byte w2=combobuf[i].walk;
11258 combobuf[i].walk=((w2& ~0x33)>>2 | (w2&0x33)<<2);
11259 w2=combobuf[i].csets;
11260 combobuf[i].csets= (((w2& ~0x50)>>1 | (w2&0x50)<<1) & ~0x0F) | (w2 & 0x0F);
11261 }
11262
11263 mark_save_dirty();
11264 break;
11265
11266 case KEY_M:
11267 if((copy!=-1)&&(copy!=zc_min(tile,tile2)))
11268 {
11269 move_combos(tile,tile2,copy,copycnt);
11270 mark_save_dirty();
11271 }
11272 break;
11273
11274 case KEY_S:
11275 tile=tile2=zc_min(tile,tile2);
11276
11277 if(copy>=0 && tile!=copy)
11278 {
11279 go_combos();
11280
11281 for(int32_t i=0; i<copycnt; i++)
11282 {
11283 zc_swap(combobuf[copy+i],combobuf[tile+i]);
11284 }
11285
11286 mark_save_dirty();
11287 setup_combo_animations();
11288 setup_combo_animations2();
11289 }
11290
11291 copy=-1;
11292 break;
11293
11294 case KEY_V:
11295 if((CHECK_CTRL_CMD) && copy != -1)
11296 {
11297 if(advpaste(tile, tile2, copy))
11298 {
11299 mark_save_dirty();
11300 copy=-1;
11301 }
11302
11303 break;
11304 }
11305
11306 masscopy=(key[KEY_LSHIFT] || key[KEY_RSHIFT])?1:0;
11307
11308 if(copy==-1)
11309 {
11310 go_combos();
11311
11312 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); i++)
11313 {
11314 combobuf[i].flip^=2;
11315 byte w2=combobuf[i].walk;
11316 combobuf[i].walk=(w2&0x55)<<1 | (w2& ~0x55)>>1;
11317 w2=combobuf[i].csets;
11318 combobuf[i].csets= (((w2&0x30)<<2 | (w2& ~0x30)>>2) & ~0x0F) | (w2 & 0x0F);
11319 }
11320
11321 mark_save_dirty();
11322 }
11323 else
11324 {
11325 go_combos();
11326 copy_combos(tile,tile2,copy,copycnt,masscopy);
11327 setup_combo_animations();
11328 setup_combo_animations2();
11329 mark_save_dirty();
11330 }
11331 break;
11332 case KEY_R:
11333 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); i++)
11334 {
11335 combobuf[i].flip = rotate_value(combobuf[i].flip);
11336 combobuf[i].walk = rotate_walk(combobuf[i].walk);
11337 combobuf[i].csets = rotate_cset(combobuf[i].csets);
11338 }
11339
11340 mark_save_dirty();
11341 break;
11342
11343 case KEY_I:
11344 {
11345 // rev.1509; Can now insert/remove all selected combos
11346 int32_t z=tile;
11347 int32_t numSelected = abs(tile-tile2) + 1;
11348 tile=zc_min(tile,tile2);
11349 tile2=MAXCOMBOS;
11350 copy = tile + numSelected; // copy=tile+1;
11351 copycnt = MAXCOMBOS-tile-numSelected; // copycnt=MAXCOMBOS-tile;
11352
11353 if(key[KEY_LSHIFT]||key[KEY_RSHIFT])
11354 {
11355 char buf[64];
11356
11357 if(numSelected>1)
11358 sprintf(buf,"Remove combos %d - %d?",tile, copy-1);
11359 else
11360 sprintf(buf,"Remove combo %d?",tile);
11361
11362 if(jwin_alert("Confirm Remove",buf,"This will offset all of the combos that follow!",NULL,"&Yes","&No",'y','n',get_zc_font(font_lfont))==1)
11363 {
11364 move_combos(tile,tile2,copy, copycnt);
11365 //don't allow the user to undo; quest combo references are incorrect -DD
11366 go_combos();
11367 mark_save_dirty();
11368 }
11369 }
11370 else
11371 {
11372 char buf[64];
11373
11374 if(numSelected>1)
11375 sprintf(buf,"Insert %d blank combos?",numSelected);
11376 else
11377 sprintf(buf,"Insert a blank combo?");
11378
11379 if(jwin_alert("Confirm Insert",buf,"This will offset all of the combos that follow!",NULL,"&Yes","&No",'y','n',get_zc_font(font_lfont))==1)
11380 {
11381 move_combos(copy,tile2,tile, copycnt);
11382 go_combos();
11383 mark_save_dirty();
11384 }
11385 }
11386
11387 copy=-1;
11388 tile2=tile=z;
11389 }
11390 break;
11391
11392 case KEY_DEL:
11393 {
11394 char buf[40];
11395
11396 if(tile==tile2)
11397 {
11398 sprintf(buf,"Delete combo %d?",tile);
11399 }
11400 else
11401 {
11402 sprintf(buf,"Delete combos %d-%d?",zc_min(tile,tile2),zc_max(tile,tile2));
11403 }
11404
11405 if(jwin_alert("Confirm Delete",buf,NULL,NULL,"&Yes","&No",'y','n',get_zc_font(font_lfont))==1)
11406 {
11407 go_combos();
11408
11409 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); i++)
11410 {
11411 clear_combo(i);
11412 }
11413
11414 tile=tile2=zc_min(tile,tile2);
11415 mark_save_dirty();
11416 setup_combo_animations();
11417 setup_combo_animations2();
11418 }
11419 }
11420 break;
11421 }
11422
11423 clear_keybuf();
11424 }
11425
11426 if(gui_mouse_b()&1)
11427 {
11428 if(isinRect(gui_mouse_x(),gui_mouse_y(),window_xofs + w + 12 - 21, window_yofs + 5, window_xofs + w +12 - 21 + 15, window_yofs + 5 + 13))
11429 {
11430 if(do_x_button(screen, w+12+window_xofs - 21, 5+window_yofs))
11431 {
11432 done=1;
11433 }
11434 }
11435
11436 int32_t x=gui_mouse_x()-screen_xofs;
11437 int32_t y=gui_mouse_y()-screen_yofs;
11438
11439 if(y>=0 && y<(208*mul))
11440 {
11441 x=zc_min(zc_max(x,0),(320*mul)-1);
11442 int32_t t;
11443
11444 t = ((x>>7)*52) + ((x>>5)&3) + ((y>>5)<<2);
11445
11446 bound(t,0,255);
11447 t+=page<<8;
11448
11449 if(key[KEY_LSHIFT] || key[KEY_RSHIFT])
11450 {
11451 tile2=t;
11452 }
11453 else
11454 {
11455 tile=tile2=t;
11456 }
11457
11458 if(tile_clicked!=t)
11459 {
11460 dclick_status=DCLICK_NOT;
11461 }
11462 else if(dclick_status == DCLICK_AGAIN)
11463 {
11464 while(gui_mouse_b()) ; // wait
11465
11466 t2 = ((x>>6)*52) + ((x>>4)&3) + ((y>>4)<<2);
11467
11468 bound(t2,0,255);
11469 t2+=page<<8;
11470
11471 if(t2!=t)
11472 {
11473 dclick_status=DCLICK_NOT;
11474 }
11475 else
11476 {
11477 go_combos();
11478 edit_combo(tile,false,cs);
11479 setup_combo_animations();
11480 setup_combo_animations2();
11481 }
11482 }
11483
11484 tile_clicked=t;
11485 }
11486 else if(x>(300*mul) && !bdown)
11487 {
11488 if(y<(224*mul)+panel_yofs && page>0)
11489 {
11490 --page;
11491 }
11492
11493 if(y>=(224*mul)+panel_yofs && page<COMBO_PAGES-1)
11494 {
11495 ++page;
11496 }
11497
11498 bdown=true;
11499 }
11500
11501 if(!bdown && isinRect(x,y,(202*mul),(213*mul)+panel_yofs,(202+44)*mul,(213+21)*mul))
11502 {
11503 FONT *tf = font;
11504 font = tfont;
11505
11506 if(do_text_button((202*mul)+screen_xofs,(213*mul)+screen_yofs+panel_yofs,(44*mul),(21*mul),"Edit"))
11507 {
11508 font = tf;
11509 edit_combo(tile,false,cs);
11510 }
11511
11512 font = tf;
11513 }
11514 else if(!bdown && isinRect(x,y,(247*mul),(213*mul)+panel_yofs,(247+44)*mul,(213+21)*mul))
11515 {
11516 FONT *tf = font;
11517 font = tfont;
11518
11519 if(do_text_button((247*mul)+screen_xofs,(213*mul)+screen_yofs+panel_yofs,(44*mul),(21*mul),"Done"))
11520 {
11521 done=1;
11522 }
11523
11524 font = tf;
11525 }
11526 else if(!bdown && isinRect(x,y,320,440+panel_yofs,320+16,440+panel_yofs+16))
11527 {
11528 FONT *tf = font;
11529 font = tfont;
11530
11531 //do_scheckbox(screen2,320,440+panel_yofs,16,jwin_pal[jcTEXTBG],jwin_pal[jcTEXTFG],combopage_animate,screen_xofs,screen_yofs);
11532 combopage_animate = combopage_animate ? 0 : 1;
11533 zc_set_config("ZQ_GUI","combopage_animate",combopage_animate);
11534
11535 font = tf;
11536 }
11537
11538 bdown=true;
11539 }
11540
11541 bool r_click = false;
11542 bool force_draw_select = false;
11543 if(gui_mouse_b()&2 && !bdown)
11544 {
11545 int32_t x=gui_mouse_x()-screen_xofs;
11546 int32_t y=gui_mouse_y()-screen_yofs;
11547
11548 if(y>=0 && y<(208*mul))
11549 {
11550 x=zc_min(zc_max(x,0),(320*mul)-1);
11551 int32_t t;
11552
11553 t = ((x>>7)*52) + ((x>>5)&3) + ((y>>5)<<2);
11554
11555 bound(t,0,255);
11556 t+=page<<8;
11557
11558 if(t<zc_min(tile,tile2) || t>zc_max(tile,tile2))
11559 {
11560 tile=tile2=t;
11561 }
11562 }
11563
11564 bdown = r_click = true;
11565 force_draw_select = true;
11566 }
11567
11568 REDRAW:
11569
11570 if(gui_mouse_b()==0)
11571 bdown=false;
11572
11573 if(otl != tile || otl2 != tile2)
11574 {
11575 otl = tile;
11576 otl2 = tile2;
11577 }
11578
11579 // if(true) // redraw every frame now. Eyeball combos need to animate regardless, and cursor blinks every 8 frames anyway.
11580 {
11581 draw_combos(page,cs,true);
11582 combo_info(tile,tile2,cs,copy,copycnt,page,6);
11583 if(force_draw_select || (framecnt&8))
11584 {
11585 int32_t x,y;
11586
11587 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); i++)
11588 {
11589 if((i>>8)==page)
11590 {
11591 int32_t t=i&255;
11592
11593 x=((t&3) + ((t/52)<<2)) << 5;
11594 y=((t%52)>>2) << 5;
11595
11596 safe_rect(screen,x+screen_xofs,y+screen_yofs,x+screen_xofs+(16*mul)-1,y+screen_yofs+(16*mul)-1,vc(CmbPgCursorCol),2);
11597 }
11598 }
11599 }
11600 }
11601 anim_hw_screen();
11602
11603 //Seriously? There is duplicate code for the r-click menu? -Gleeok
11604 if(r_click)
11605 {
11606 NewMenu rcmenu
11607 {
11608 { "Copy", [&]()
11609 {
11610 go_combos();
11611 copy=zc_min(tile,tile2);
11612 copycnt=abs(tile-tile2)+1;
11613 } },
11614 { "Paste", [&]()
11615 {
11616 if((CHECK_CTRL_CMD))
11617 {
11618 if(advpaste(tile, tile2, copy))
11619 {
11620 mark_save_dirty();
11621 copy=-1;
11622 }
11623 return;
11624 }
11625
11626 masscopy=(key[KEY_LSHIFT] || key[KEY_RSHIFT])?1:0;
11627
11628 go_combos();
11629 copy_combos(tile,tile2,copy,copycnt,masscopy);
11630 setup_combo_animations();
11631 setup_combo_animations2();
11632 mark_save_dirty();
11633 }, nullopt, copy < 0 ? MFL_DIS : 0 },
11634 { "Adv. Paste", [&]()
11635 {
11636 if(advpaste(tile, tile2, copy))
11637 {
11638 mark_save_dirty();
11639 copy=-1;
11640 }
11641 }, nullopt, copy < 0 ? MFL_DIS : 0 },
11642 { "Move", [&]()
11643 {
11644 if(copy!=zc_min(tile,tile2))
11645 {
11646 move_combos(tile,tile2,copy,copycnt);
11647 mark_save_dirty();
11648 setup_combo_animations();
11649 setup_combo_animations2();
11650 }
11651 }, nullopt, copy < 0 ? MFL_DIS : 0 },
11652 { "Swap", [&]()
11653 {
11654 tile=tile2=zc_min(tile,tile2);
11655
11656 if(tile!=copy)
11657 {
11658 go_combos();
11659
11660 for(int32_t i=0; i<copycnt; i++)
11661 {
11662 zc_swap(combobuf[copy+i],combobuf[tile+i]);
11663 }
11664
11665 mark_save_dirty();
11666 setup_combo_animations();
11667 setup_combo_animations2();
11668 }
11669 copy=-1;
11670 }, nullopt, copy < 0 ? MFL_DIS : 0 },
11671 { "Delete", [&]()
11672 {
11673 string msg;
11674
11675 if(tile==tile2)
11676 msg = fmt::format("Delete combo {}?",tile);
11677 else
11678 msg = fmt::format("Delete combos {}-{}?",zc_min(tile,tile2),zc_max(tile,tile2));
11679 bool didconfirm = false;
11680 AlertDialog("Confirm Delete",msg,
11681 [&](bool ret,bool)
11682 {
11683 if(ret)
11684 didconfirm = true;
11685 }).show();
11686 if(didconfirm)
11687 {
11688 go_combos();
11689
11690 for(int32_t i=zc_min(tile,tile2); i<=zc_max(tile,tile2); i++)
11691 clear_combo(i);
11692
11693 tile=tile2=zc_min(tile,tile2);
11694 mark_save_dirty();
11695 }
11696 } },
11697 {},
11698 { "Edit", [&]()
11699 {
11700 go_combos();
11701 edit_combo(tile,false,cs);
11702 } },
11703 { "Insert", [&]()
11704 {
11705 int z = tile;
11706 int count = abs(tile-tile2)+1;
11707 tile = zc_min(tile,tile2);
11708 tile2 = MAXCOMBOS;
11709 copy = tile+count;
11710 copycnt = MAXCOMBOS-tile-count;
11711
11712 string msg;
11713
11714 if(count>1)
11715 msg = fmt::format("Insert combos {} - {}?"
11716 " This will offset all of the combos that follow!",tile, copy-1);
11717 else
11718 msg = fmt::format("Insert combo {}?"
11719 " This will offset all of the combos that follow!",tile);
11720
11721 bool didconfirm = false;
11722 AlertDialog("Confirm Insert",msg,
11723 [&](bool ret,bool)
11724 {
11725 if(ret)
11726 didconfirm = true;
11727 }).show();
11728 if(didconfirm)
11729 move_combos(copy, tile2, tile, copycnt);
11730 else return;
11731
11732 copy = -1;
11733 tile2 = tile = z;
11734
11735 //don't allow the user to undo; quest combo references are incorrect -DD
11736 go_combos();
11737 mark_save_dirty();
11738 } },
11739 { "Remove", [&]()
11740 {
11741 int z = tile;
11742 int count = abs(tile-tile2)+1;
11743 tile = zc_min(tile,tile2);
11744 tile2 = MAXCOMBOS;
11745 copy = tile+count;
11746 copycnt = MAXCOMBOS-tile-count;
11747
11748 string msg;
11749
11750 if(count>1)
11751 msg = fmt::format("Remove combos {} - {}?"
11752 " This will offset all of the combos that follow!",tile, copy-1);
11753 else
11754 msg = fmt::format("Remove combo {}?"
11755 " This will offset all of the combos that follow!",tile);
11756
11757 bool didconfirm = false;
11758 AlertDialog("Confirm Remove",msg,
11759 [&](bool ret,bool)
11760 {
11761 if(ret)
11762 didconfirm = true;
11763 }).show();
11764 if(didconfirm)
11765 move_combos(tile, tile2, copy, copycnt);
11766 else return;
11767
11768 copy = -1;
11769 tile2 = tile = z;
11770
11771 //don't allow the user to undo; quest combo references are incorrect -DD
11772 go_combos();
11773 mark_save_dirty();
11774 } },
11775 {},
11776 { "Locations", [&]()
11777 {
11778 int32_t z = Combo;
11779 Combo = tile;
11780 onComboLocationReport();
11781 Combo = z;
11782 } },
11783 };
11784 rcmenu.pop(window_mouse_x(),window_mouse_y());
11785 r_click = false;
11786 goto REDRAW;
11787 }
11788
11789 }
11790 while(!done);
11791
11792 while(gui_mouse_b()) ; // wait
11793 setup_combo_animations();
11794 setup_combo_animations2();
11795 _selected_combo = tile;
11796 _selected_cset = cs;
11797 popup_zqdialog_end();
11798 return done-1;
11799 }
11800
11801 int32_t onCombos()
11802 {
11803 combo_screen(-1,-1);
11804 refresh(rALL);
11805 return D_O_K;
11806 }
11807
11808 12 static newcombo curr_combo;
11809 int32_t d_combo_loader(int32_t msg,DIALOG *d,int32_t c)
11810 {
11811 //these are here to bypass compiler warnings about unused arguments
11812 c=c;
11813
11814 if(msg==MSG_DRAW)
11815 {
11816 FONT *f = get_zc_font(font_lfont_l);
11817 textprintf_ex(screen,f,d->x,d->y,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"Tile:");
11818 textprintf_ex(screen,f,d->x+((1.5)*36),d->y,jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",curr_combo.o_tile);
11819 textprintf_ex(screen,f,d->x,d->y+(14),jwin_pal[jcBOXFG],jwin_pal[jcBOX],"Flip:");
11820 textprintf_ex(screen,f,d->x+((1.5)*36),d->y+(14),jwin_pal[jcBOXFG],jwin_pal[jcBOX],"%d",curr_combo.flip);
11821 textprintf_ex(screen,f,d->x,d->y+(36),jwin_pal[jcBOXFG],jwin_pal[jcBOX],"CSet2:");
11822 }
11823
11824 return D_O_K;
11825 }
11826
11827 bool call_combo_editor(int32_t);
11828 bool edit_combo(int32_t c,bool freshen,int32_t cs)
11829 {
11830 FONT* ofont = font;
11831 //CSet = cs;
11832 reset_combo_animations();
11833 reset_combo_animations2();
11834 bool edited = call_combo_editor(c);
11835 font = ofont;
11836
11837 if(freshen)
11838 {
11839 refresh(rALL);
11840 }
11841
11842 setup_combo_animations();
11843 setup_combo_animations2();
11844
11845 return edited;
11846 }
11847
11848 int32_t d_itile_proc(int32_t msg,DIALOG *d,int32_t)
11849 {
11850 switch(msg)
11851 {
11852 case MSG_CLICK:
11853 {
11854 int32_t cs = d->d2;
11855 int32_t flip = 0;
11856
11857 if(select_tile(d->d1,flip,1,cs,true))
11858 {
11859 int32_t ok=1;
11860
11861 if(newtilebuf[d->d1].format==tf8Bit)
11862 jwin_alert("Warning",
11863 "You have selected an 8-bit tile.",
11864 "It will not be drawn correctly",
11865 "on the file select screen.",
11866 "&OK",NULL,'o',0,get_zc_font(font_lfont));
11867
11868 return D_REDRAW;
11869 }
11870 }
11871 break;
11872
11873 case MSG_DRAW:
11874 d->w = 32+4;
11875 d->h = 32+4;
11876
11877 BITMAP *buf = create_bitmap_ex(8,16,16);
11878 BITMAP *bigbmp = create_bitmap_ex(8,d->w,d->h);
11879
11880 if(buf && bigbmp)
11881 {
11882 clear_bitmap(buf);
11883 overtile16(buf,d->d1,0,0,d->fg,0);
11884 stretch_blit(buf, bigbmp, 0,0, 16, 16, 2, 2, d->w-4, d->h-4);
11885 destroy_bitmap(buf);
11886 jwin_draw_frame(bigbmp,0, 0, d->w,d->h, FR_DEEP);
11887 blit(bigbmp,screen,0,0,d->x-1,d->y-1,d->w,d->h);
11888 destroy_bitmap(bigbmp);
11889 }
11890
11891 break;
11892 }
11893
11894 return D_O_K;
11895 }
11896
11897 static DIALOG icon_dlg[] =
11898 {
11899 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) */
11900 { jwin_win_proc, 70, 70, 170, 104, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *) "Game Icons", NULL, NULL },
11901 { d_timer_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
11902 { d_itile_proc, 108+3, 112, 20, 20, 0, 0, 0, 0, 0, 6, NULL, NULL, NULL },
11903 { d_itile_proc, 138+3, 112, 20, 20, 0, 0, 0, 0, 0, 7, NULL, NULL, NULL },
11904 { d_itile_proc, 168+3, 112, 20, 20, 0, 0, 0, 0, 0, 8, NULL, NULL, NULL },
11905 { d_itile_proc, 198+3, 112, 20, 20, 0, 0, 0, 0, 0, 9, NULL, NULL, NULL },
11906 { jwin_button_proc, 90, 145, 61, 21, vc(14), vc(1), 13, D_EXIT, 0, 0, (void *) "OK", NULL, NULL },
11907 { jwin_button_proc, 170, 145, 61, 21, vc(14), vc(1), 27, D_EXIT, 0, 0, (void *) "Cancel", NULL, NULL },
11908 { jwin_text_proc, 108+11, 98, 8, 9, 0, 0, 0, 0, 0, 0, (void *) "0", NULL, NULL },
11909 { jwin_text_proc, 138+11, 98, 8, 9, 0, 0, 0, 0, 0, 0, (void *) "1", NULL, NULL },
11910 { jwin_text_proc, 168+11, 98, 8, 9, 0, 0, 0, 0, 0, 0, (void *) "2", NULL, NULL },
11911 { jwin_text_proc, 198+11, 98, 8, 9, 0, 0, 0, 0, 0, 0, (void *) "3+", NULL, NULL },
11912 { jwin_text_proc, 88, 98, 12, 9, 0, 0, 0, 0, 0, 0, (void *) "Ring:", NULL, NULL },
11913 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
11914 };
11915
11916 int32_t onIcons()
11917 {
11918 PALETTE pal;
11919 memcpy(pal,RAMpal,sizeof(RAMpal));
11920 icon_dlg[0].dp2=get_zc_font(font_lfont);
11921
11922 for(int32_t i=0; i<4; i++)
11923 {
11924 icon_dlg[i+2].d1 = QMisc.icons[i];
11925 icon_dlg[i+2].fg = i+6;
11926 load_cset(pal, i+6, pSprite(i+spICON1));
11927 }
11928
11929 zc_set_palette(pal);
11930
11931 large_dialog(icon_dlg);
11932
11933 int32_t ret = do_zqdialog(icon_dlg,7);
11934
11935 if(ret==6)
11936 {
11937 for(int32_t i=0; i<4; i++)
11938 {
11939 if(QMisc.icons[i] != icon_dlg[i+2].d1)
11940 {
11941 QMisc.icons[i] = icon_dlg[i+2].d1;
11942 mark_save_dirty();
11943 }
11944 }
11945 }
11946
11947 zc_set_palette(RAMpal);
11948 return D_O_K;
11949 }
11950
11951 // Identical to jwin_frame_proc, but is treated differently by large_dialog()
11952 int32_t d_comboframe_proc(int32_t msg, DIALOG *d, int32_t)
11953 {
11954 if(msg == MSG_DRAW)
11955 {
11956 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
11957 }
11958
11959 return D_O_K;
11960 }
11961
11962 int32_t d_combo_proc(int32_t msg,DIALOG *d,int32_t)
11963 {
11964 switch(msg)
11965 {
11966 case MSG_CLICK:
11967 {
11968 if((d->flags&D_NOCLICK))
11969 break;
11970
11971 int32_t ret = (d->flags & D_EXIT) ? D_CLOSE : D_O_K;
11972 int32_t combo2;
11973 int32_t cs;
11974
11975 if(CHECK_ALT) //place selected cmb/cs
11976 {
11977 if(gui_mouse_b()&1)
11978 {
11979 if(!CHECK_SHIFT)
11980 d->d1 = Combo;
11981 d->fg = CSet;
11982 }
11983
11984 return ret|D_REDRAW;
11985 }
11986 else if(gui_mouse_b()&2||nextcombo_fake_click==2) //clear to 0/0
11987 {
11988 d->d1=0;
11989 d->fg=0;
11990 return ret|D_REDRAW;
11991 }
11992 else if(gui_mouse_b()&1||nextcombo_fake_click==1) //popup combo picker
11993 {
11994 combo2=d->d1;
11995 cs=d->fg;
11996
11997 if((CHECK_CTRL_CMD ? select_combo_3 : select_combo_2)(combo2, cs))
11998 {
11999 d->d1=combo2;
12000 d->fg=cs;
12001 }
12002
12003 return ret|D_REDRAW;
12004 }
12005 else return ret|D_REDRAWME;
12006 }
12007 break;
12008
12009 case MSG_DRAW:
12010 {
12011 d->w = 32;
12012 d->h = 32;
12013
12014 BITMAP *buf = create_bitmap_ex(8,16,16);
12015 BITMAP *bigbmp = create_bitmap_ex(8,d->w,d->h);
12016
12017 if(buf && bigbmp)
12018 {
12019 clear_bitmap(buf);
12020
12021 if(d->d1==-1) // Display curr_combo instead of combobuf
12022 {
12023 newcombo hold = combobuf[0];
12024 combobuf[0] = curr_combo;
12025 putcombo(buf,0,0,0,d->fg);
12026 combobuf[0] = hold;
12027 }
12028 else if(d->d1)
12029 {
12030 putcombo(buf,0,0,d->d1,d->fg);
12031 }
12032
12033 stretch_blit(buf, bigbmp, 0,0, 16, 16, 0, 0, d->w, d->h);
12034 destroy_bitmap(buf);
12035 blit(bigbmp,screen,0,0,d->x-1,d->y-1,d->w,d->h);
12036 destroy_bitmap(bigbmp);
12037 }
12038 }
12039 break;
12040 }
12041 return D_O_K;
12042 }
12043
12044 // Hey, let's have a few hundred more lines of code, why not.
12045
12046 #define MR_4BIT 0
12047 #define MR_8BIT 1
12048
12049 static byte massRecolorSrc4Bit[16]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
12050 static byte massRecolorDest4Bit[16]={ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
12051 static word massRecolor8BitCSets=0; // Which CSets are affected? One bit each.
12052
12053 static byte massRecolorSrc8Bit[16]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
12054 static byte massRecolorDest8Bit[16]={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
12055
12056 static int32_t massRecolorDraggedColor=-1;
12057 static int32_t massRecolorCSet;
12058 static bool massRecolorIgnoreBlank=true;
12059 static byte massRecolorType=MR_4BIT;
12060
12061 // Shows the sets of colors to replace from/to.
12062 // D_CSET: Colors are 0-15 within the current CSet rather than absolute.
12063 // D_SETTABLE: Colors can be dragged and dropped onto this one.
12064 #define D_CSET D_USER
12065 #define D_SETTABLE (D_USER<<1)
12066 int32_t d_mr_cset_proc(int32_t msg, DIALOG* d, int32_t)
12067 {
12068 BITMAP* bmp=screen;
12069 int32_t colorWidth=(d->w-4)/16;
12070 byte* colors=static_cast<byte*>(d->dp);
12071
12072 switch(msg)
12073 {
12074 case MSG_DRAW:
12075 {
12076 jwin_draw_frame(bmp, d->x, d->y, d->w, d->h, FR_DEEP);
12077
12078 int32_t baseColor=((d->flags&D_CSET)!=0) ? massRecolorCSet*16 : 0;
12079 for(int32_t c=0; c<16; c++)
12080 {
12081 rectfill(bmp,
12082 d->x+2+c*colorWidth, d->y+2,
12083 d->x+2+((c+1)*colorWidth)-1, d->y+2+d->h-5,
12084 baseColor+colors[c]);
12085 }
12086 }
12087 break;
12088
12089 case MSG_LPRESS:
12090 {
12091 int32_t x=(gui_mouse_x()-(d->x+2))/colorWidth;
12092
12093 if(x >= 0 && x < 16) //sanity check!
12094 {
12095 massRecolorDraggedColor=colors[x];
12096 }
12097 }
12098 break;
12099
12100 case MSG_LRELEASE: // This isn't exactly right, but it'll do...
12101 if((d->flags&D_SETTABLE)!=0 && massRecolorDraggedColor>=0)
12102 {
12103 int32_t x=(gui_mouse_x()-(d->x+2))/colorWidth;
12104 if(x >= 0 && x < 16) //sanity check!
12105 {
12106 colors[x]=massRecolorDraggedColor;
12107 d->flags|=D_DIRTY;
12108 }
12109 }
12110 massRecolorDraggedColor=-1;
12111 break;
12112 }
12113
12114 return D_O_K;
12115 }
12116
12117 // Used for the full palette in 8-bit mode.
12118 static int32_t d_mr_palette_proc(int32_t msg, DIALOG* d, int32_t)
12119 {
12120 BITMAP* bmp=screen;
12121 int colorWidth=(d->w-4)/16;
12122 d->h = 4+(colorWidth*14);
12123 int colorHeight=colorWidth;
12124
12125 switch(msg)
12126 {
12127 case MSG_DRAW:
12128 {
12129 jwin_draw_frame(bmp, d->x, d->y, d->w, d->h, FR_DEEP);
12130 for(int cset=0; cset<=13; cset++)
12131 {
12132 for(int color=0; color<16; color++)
12133 {
12134 rectfill(bmp,
12135 d->x+2+color*colorWidth,
12136 d->y+2+cset*colorHeight,
12137 d->x+2+((color+1)*colorWidth)-1,
12138 d->y+2+((cset+1)*colorHeight)-1,
12139 cset*16+color);
12140 }
12141 }
12142 }
12143 break;
12144
12145 case MSG_LPRESS:
12146 {
12147 int cset=(gui_mouse_y()-(d->y+2))/colorHeight;
12148 int color=(gui_mouse_x()-(d->x+2))/colorWidth;
12149 massRecolorDraggedColor=cset*16+color;
12150 }
12151 break;
12152 }
12153
12154 return D_O_K;
12155 }
12156
12157 static DIALOG recolor_4bit_dlg[] =
12158 {
12159 // (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp)
12160 { jwin_win_proc, 0, 0, 216, 224, 0, 0, 0, D_EXIT, 0, 0, (void *) "Recolor setup", NULL, NULL },
12161
12162 // 1
12163 { jwin_text_proc, 12, 32, 176, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "From", NULL, NULL },
12164 { d_mr_cset_proc, 10, 42, 196, 16, 0, 0, 0, D_CSET, 0, 0, (void *)massRecolorSrc4Bit, NULL, NULL },
12165 { jwin_text_proc, 12, 60, 176, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "To", NULL, NULL },
12166 { d_mr_cset_proc, 10, 70, 196, 16, 0, 0, 0, D_CSET|D_SETTABLE, 0, 0, (void *)massRecolorDest4Bit, NULL, NULL },
12167
12168 // 5
12169 { jwin_text_proc, 12, 96, 176, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "Apply to which CSets in 8-bit tiles?", NULL, NULL },
12170 { jwin_check_proc, 12, 112, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "0", NULL, NULL },
12171 { jwin_check_proc, 36, 112, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "1", NULL, NULL },
12172 { jwin_check_proc, 60, 112, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "2", NULL, NULL },
12173 { jwin_check_proc, 84, 112, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "3", NULL, NULL },
12174 { jwin_check_proc, 108, 112, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "4", NULL, NULL },
12175 { jwin_check_proc, 132, 112, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "5", NULL, NULL },
12176 { jwin_check_proc, 156, 112, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "6", NULL, NULL },
12177 { jwin_check_proc, 12, 128, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "7", NULL, NULL },
12178 { jwin_check_proc, 36, 128, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "8", NULL, NULL },
12179 { jwin_check_proc, 60, 128, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "9", NULL, NULL },
12180 { jwin_check_proc, 84, 128, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "10", NULL, NULL },
12181 { jwin_check_proc, 108, 128, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "11", NULL, NULL },
12182 { jwin_check_proc, 132, 128, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "12", NULL, NULL },
12183 { jwin_check_proc, 156, 128, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "13", NULL, NULL },
12184
12185 // 20
12186 { jwin_check_proc, 12, 144, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "Ignore blank tiles", NULL, NULL },
12187 { jwin_func_button_proc, 14, 160, 60, 20, vc(14), vc(1), 0, 0, 0, 0, (void *) "Reset", NULL, (void*)massRecolorReset4Bit },
12188 { jwin_button_proc, 82, 160, 120, 20, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *) "Switch to 8-bit mode", NULL, NULL },
12189 { jwin_button_proc, 44, 188, 60, 20, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *) "OK", NULL, NULL },
12190 { jwin_button_proc, 112, 188, 60, 20, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *) "Cancel", NULL, NULL },
12191
12192 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
12193 };
12194
12195 #define MR4_SRC_COLORS 2
12196 #define MR4_DEST_COLORS 4
12197 #define MR4_8BIT_EFFECT_START 6
12198 #define MR4_IGNORE_BLANK 20
12199 #define MR4_RESET 21
12200 #define MR4_SWITCH 22
12201 #define MR4_OK 23
12202 #define MR4_CANCEL 24
12203
12204 static DIALOG recolor_8bit_dlg[] =
12205 {
12206 // (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp)
12207 { jwin_win_proc, 0, 0, 288, 224, 0, 0, 0, D_EXIT, 0, 0, (void *) "Recolor setup", NULL, NULL },
12208
12209 // 1
12210 { jwin_text_proc, 12, 32, 176, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "From", NULL, NULL },
12211 { d_mr_cset_proc, 10, 42, 132, 12, 0, 0, 0, D_SETTABLE, 0, 0, (void *)massRecolorSrc8Bit, NULL, NULL },
12212 { jwin_text_proc, 12, 60, 176, 8, vc(15), vc(1), 0, 0, 0, 0, (void *) "To", NULL, NULL },
12213 { d_mr_cset_proc, 10, 70, 132, 12, 0, 0, 0, D_SETTABLE, 0, 0, (void *)massRecolorDest8Bit, NULL, NULL },
12214 { d_mr_palette_proc, 144, 32, 132, 150, vc(15), vc(1), 0, 0, 0, 0, (void *) NULL, NULL, NULL },
12215
12216 // 6
12217 { jwin_check_proc, 12, 144, 168, 8, vc(15), vc(1), 0, 0, 1, 0, (void *) "Ignore blank tiles", NULL, NULL },
12218 { jwin_func_button_proc, 50, 160, 60, 20, vc(14), vc(1), 0, 0, 0, 0, (void *) "Reset", NULL, (void*)massRecolorReset8Bit },
12219 { jwin_button_proc, 118, 160, 120, 20, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *) "Switch to 4-bit mode", NULL, NULL },
12220 { jwin_button_proc, 80, 188, 60, 20, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *) "OK", NULL, NULL },
12221 { jwin_button_proc, 148, 188, 60, 20, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *) "Cancel", NULL, NULL },
12222
12223 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
12224 };
12225
12226 #define MR8_SRC_COLORS 2
12227 #define MR8_DEST_COLORS 4
12228 #define MR8_PALETTE 5
12229 #define MR8_IGNORE_BLANK 6
12230 #define MR8_RESET 7
12231 #define MR8_SWITCH 8
12232 #define MR8_OK 9
12233 #define MR8_CANCEL 10
12234
12235 static void massRecolorInit(int32_t cset)
12236 {
12237 massRecolorDraggedColor=-1;
12238 massRecolorCSet=cset;
12239
12240 recolor_4bit_dlg[0].dp2=get_zc_font(font_lfont);
12241 recolor_8bit_dlg[0].dp2=get_zc_font(font_lfont);
12242
12243 for(int32_t i=0; i<=13; i++)
12244 {
12245 if((massRecolor8BitCSets&(1<<i))!=0)
12246 recolor_4bit_dlg[MR4_8BIT_EFFECT_START+i].flags|=D_SELECTED;
12247 else
12248 recolor_4bit_dlg[MR4_8BIT_EFFECT_START+i].flags&=~D_SELECTED;
12249 }
12250
12251 if(massRecolorIgnoreBlank)
12252 {
12253 recolor_4bit_dlg[MR4_IGNORE_BLANK].flags|=D_SELECTED;
12254 recolor_8bit_dlg[MR8_IGNORE_BLANK].flags|=D_SELECTED;
12255 }
12256 else
12257 {
12258 recolor_4bit_dlg[MR4_IGNORE_BLANK].flags&=~D_SELECTED;
12259 recolor_8bit_dlg[MR8_IGNORE_BLANK].flags&=~D_SELECTED;
12260 }
12261
12262 large_dialog(recolor_4bit_dlg);
12263 large_dialog(recolor_8bit_dlg);
12264
12265 // Quick fix for large_dialog() screwing these up. It's ugly. Whatever.
12266 if((recolor_4bit_dlg[MR4_DEST_COLORS].w-4)%4!=0)
12267 {
12268 recolor_4bit_dlg[MR4_SRC_COLORS].x++;
12269 recolor_4bit_dlg[MR4_SRC_COLORS].w-=2;
12270 recolor_4bit_dlg[MR4_DEST_COLORS].x++;
12271 recolor_4bit_dlg[MR4_DEST_COLORS].w-=2;
12272
12273 recolor_8bit_dlg[MR8_SRC_COLORS].x++;
12274 recolor_8bit_dlg[MR8_SRC_COLORS].w-=2;
12275 recolor_8bit_dlg[MR8_DEST_COLORS].x++;
12276 recolor_8bit_dlg[MR8_DEST_COLORS].w-=2;
12277 recolor_8bit_dlg[MR8_PALETTE].x++;
12278 recolor_8bit_dlg[MR8_PALETTE].w-=2;
12279 recolor_8bit_dlg[MR8_PALETTE].y++;
12280 recolor_8bit_dlg[MR8_PALETTE].h-=2;
12281 }
12282 }
12283
12284 static void massRecolorApplyChanges()
12285 {
12286 massRecolor8BitCSets=0;
12287 for(int32_t i=0; i<=13; i++)
12288 {
12289 if((recolor_4bit_dlg[MR4_8BIT_EFFECT_START+i].flags&D_SELECTED)!=0)
12290 massRecolor8BitCSets|=1<<i;
12291 }
12292
12293 if(massRecolorType==MR_4BIT)
12294 massRecolorIgnoreBlank=(recolor_4bit_dlg[MR4_IGNORE_BLANK].flags&D_SELECTED)!=0;
12295 else
12296 massRecolorIgnoreBlank=(recolor_8bit_dlg[MR8_IGNORE_BLANK].flags&D_SELECTED)!=0;
12297 }
12298
12299 static bool massRecolorSetup(int32_t cset)
12300 {
12301 massRecolorInit(cset);
12302
12303 // Remember the current colors in case the user cancels.
12304 int32_t oldDest4Bit[16], oldSrc8Bit[16], oldDest8Bit[16];
12305 for(int32_t i=0; i<16; i++)
12306 {
12307 oldDest4Bit[i]=massRecolorDest4Bit[i];
12308 oldSrc8Bit[i]=massRecolorSrc8Bit[i];
12309 oldDest8Bit[i]=massRecolorDest8Bit[i];
12310 }
12311
12312 byte type=massRecolorType;
12313 int32_t ret;
12314 do
12315 {
12316 HANDLE_CLOSE_ZQDLG();
12317 if(exiting_program) break;
12318 if(type==MR_4BIT)
12319 {
12320 ret=do_zqdialog(recolor_4bit_dlg, MR4_OK);
12321 if(ret==MR4_SWITCH)
12322 type=MR_8BIT;
12323 }
12324 else
12325 {
12326 ret=do_zqdialog(recolor_8bit_dlg, MR8_OK);
12327 if(ret==MR8_SWITCH)
12328 type=MR_4BIT;
12329 }
12330 } while(ret==MR4_SWITCH || ret==MR8_SWITCH);
12331
12332 if(ret!=MR4_OK && ret!=MR8_OK) // Canceled
12333 {
12334 for(int32_t i=0; i<16; i++)
12335 {
12336 massRecolorDest4Bit[i]=oldDest4Bit[i];
12337 massRecolorSrc8Bit[i]=oldSrc8Bit[i];
12338 massRecolorDest8Bit[i]=oldDest8Bit[i];
12339 }
12340 return false;
12341 }
12342
12343 // OK
12344 massRecolorType=type;
12345 massRecolorApplyChanges();
12346 return true;
12347 }
12348
12349 static void massRecolorApply4Bit(int32_t tile)
12350 {
12351 byte buf[256];
12352 unpack_tile(newtilebuf, tile, 0, true);
12353
12354 if(newtilebuf[tile].format==tf4Bit)
12355 {
12356 for(int32_t i=0; i<256; i++)
12357 buf[i]=massRecolorDest4Bit[unpackbuf[i]];
12358 }
12359 else // 8-bit
12360 {
12361 for(int32_t i=0; i<256; i++)
12362 {
12363 word cset=unpackbuf[i]>>4;
12364 if((massRecolor8BitCSets&(1<<cset))!=0) // Recolor this CSet?
12365 {
12366 word color=unpackbuf[i]&15;
12367 buf[i]=(cset<<4)|massRecolorDest4Bit[color];
12368 }
12369 else
12370 buf[i]=unpackbuf[i];
12371 }
12372 }
12373
12374 pack_tile(newtilebuf, buf, tile);
12375 }
12376
12377 static void massRecolorApply8Bit(int32_t tile)
12378 {
12379 byte buf[256];
12380 unpack_tile(newtilebuf, tile, 0, true);
12381
12382 for(int32_t i=0; i<256; i++)
12383 {
12384 byte color=unpackbuf[i];
12385 for(int32_t j=0; j<16; j++)
12386 {
12387 if(massRecolorSrc8Bit[j]==color)
12388 {
12389 color=massRecolorDest8Bit[j];
12390 break;
12391 }
12392 }
12393 buf[i]=color;
12394 }
12395
12396 pack_tile(newtilebuf, buf, tile);
12397 }
12398
12399 static void massRecolorApply(int32_t tile)
12400 {
12401 if(massRecolorIgnoreBlank && blank_tile_table[tile])
12402 return;
12403
12404 if(massRecolorType==MR_4BIT)
12405 massRecolorApply4Bit(tile);
12406 else // 8-bit
12407 {
12408 if(newtilebuf[tile].format==tf4Bit)
12409 return;
12410 massRecolorApply8Bit(tile);
12411 }
12412 }
12413
12414 static void massRecolorReset4Bit()
12415 {
12416 for(int32_t i=0; i<16; i++)
12417 massRecolorDest4Bit[i]=i;
12418 recolor_4bit_dlg[MR4_DEST_COLORS].flags|=D_DIRTY;
12419 }
12420
12421 static void massRecolorReset8Bit()
12422 {
12423 for(int32_t i=0; i<16; i++)
12424 {
12425 massRecolorSrc8Bit[i]=0;
12426 massRecolorDest8Bit[i]=0;
12427 }
12428
12429 recolor_8bit_dlg[MR8_SRC_COLORS].flags|=D_DIRTY;
12430 recolor_8bit_dlg[MR8_DEST_COLORS].flags|=D_DIRTY;
12431 }
12432
12433 1 void center_zq_tiles_dialogs()
12434 {
12435 1 jwin_center_dialog(create_relational_tiles_dlg);
12436 1 jwin_center_dialog(icon_dlg);
12437 1 jwin_center_dialog(leech_dlg);
12438 1 jwin_center_dialog(move_textbox_list_dlg);
12439 1 jwin_center_dialog(recolor_4bit_dlg);
12440 1 jwin_center_dialog(recolor_8bit_dlg);
12441 1 }
12442
12443 //.ZCOMBO
12444
12445 int32_t readcombo_loop(PACKFILE* f, word section_version, newcombo& temp_combo);
12446 int32_t writecombo_loop(PACKFILE *f, word section_version, newcombo const& tmp_cmb);
12447
12448 int32_t readcombofile_old(PACKFILE *f, int32_t skip, byte nooverwrite, int32_t zversion,
12449 dword section_version, int32_t index, int32_t count)
12450 {
12451 byte tempbyte;
12452 newcombo temp_combo;
12453 for ( int32_t tilect = 0; tilect < count; tilect++ )
12454 {
12455 int32_t temp_trigflags[3] = {0};
12456 temp_combo.clear();
12457 combo_trigger& temp_trigger = temp_combo.triggers.emplace_back();
12458 if(!p_igetw(&temp_combo.tile,f))
12459 {
12460 return 0;
12461 }
12462 temp_combo.o_tile = temp_combo.tile;
12463
12464 if(!p_getc(&temp_combo.flip,f))
12465 {
12466 return 0;
12467 }
12468
12469 if(!p_getc(&temp_combo.walk,f))
12470 {
12471 return 0;
12472 }
12473
12474 if(!p_getc(&temp_combo.type,f))
12475 {
12476 return 0;
12477 }
12478
12479 if(!p_getc(&temp_combo.csets,f))
12480 {
12481 return 0;
12482 }
12483
12484 if(!p_getc(&temp_combo.frames,f))
12485 {
12486 return 0;
12487 }
12488
12489 if(!p_getc(&temp_combo.speed,f))
12490 {
12491 return 0;
12492 }
12493
12494 if(!p_igetw(&temp_combo.nextcombo,f))
12495 {
12496 return 0;
12497 }
12498
12499 if(!p_getc(&temp_combo.nextcset,f))
12500 {
12501 return 0;
12502 }
12503
12504 if(!p_getc(&temp_combo.flag,f))
12505 {
12506 return 0;
12507 }
12508
12509 if(!p_getc(&temp_combo.skipanim,f))
12510 {
12511 return 0;
12512 }
12513
12514 if(!p_igetw(&temp_combo.nexttimer,f))
12515 {
12516 return 0;
12517 }
12518
12519 if(!p_getc(&temp_combo.skipanimy,f))
12520 {
12521 return 0;
12522 }
12523
12524 if(!p_getc(&temp_combo.animflags,f))
12525 {
12526 return 0;
12527 }
12528
12529 //2.55 starts here
12530 if ( zversion >= 0x255 )
12531 {
12532 if ( section_version >= 12 )
12533 {
12534 for ( int32_t q = 0; q < NUM_COMBO_ATTRIBUTES; q++ )
12535 {
12536 if(!p_igetl(&temp_combo.attributes[q],f))
12537 {
12538 return 0;
12539 }
12540 }
12541 if(!p_igetl(&temp_combo.usrflags,f))
12542 {
12543 return 0;
12544 }
12545 for ( int32_t q = 0; q < 3; q++ )
12546 {
12547 if(!p_igetl(&temp_trigflags[q],f))
12548 return 0;
12549 }
12550
12551 if(!p_igetl(&temp_trigger.triggerlevel,f))
12552 {
12553 return 0;
12554 }
12555 if(section_version >= 22)
12556 {
12557 if(!p_getc(&temp_trigger.triggerbtn,f))
12558 {
12559 return 0;
12560 }
12561 }
12562 if(section_version < 23)
12563 {
12564 switch(temp_combo.type) // TRIGFLAG_CMBTYPEFX now required for combotype-specific effects
12565 {
12566 case cSCRIPT1: case cSCRIPT2: case cSCRIPT3: case cSCRIPT4: case cSCRIPT5:
12567 case cSCRIPT6: case cSCRIPT7: case cSCRIPT8: case cSCRIPT9: case cSCRIPT10:
12568 case cTRIGGERGENERIC: case cCSWITCH:
12569 temp_trigflags[TRIGFLAG_CMBTYPEFX/32] |= 1 << (TRIGFLAG_CMBTYPEFX%32);
12570 }
12571 }
12572 if(section_version >= 24)
12573 {
12574 if(!p_getc(&temp_trigger.triggeritem,f))
12575 {
12576 return 0;
12577 }
12578 if(!p_getc(&tempbyte, f))
12579 return 0;
12580 temp_trigger.trigtimer = tempbyte;
12581 }
12582 if(section_version >= 25)
12583 {
12584 if(!p_getc(&temp_trigger.trigsfx,f))
12585 {
12586 return 0;
12587 }
12588 }
12589 else
12590 {
12591 switch(temp_combo.type)
12592 {
12593 case cLOCKBLOCK: case cBOSSLOCKBLOCK:
12594 if(!(temp_combo.usrflags & cflag3))
12595 temp_combo.attribytes[3] = WAV_DOOR;
12596 temp_combo.usrflags &= ~cflag3;
12597 break;
12598 }
12599 }
12600 if(section_version < 26)
12601 {
12602 if(temp_combo.type == cARMOS)
12603 {
12604 if(temp_combo.usrflags & cflag1)
12605 temp_combo.usrflags |= cflag3;
12606 }
12607 }
12608 if(section_version >= 27)
12609 {
12610 if(!p_igetl(&temp_trigger.trigchange,f))
12611 {
12612 return qe_invalid;
12613 }
12614 }
12615 else
12616 {
12617 if(temp_trigflags[0] & 0x00040000) //'next'
12618 temp_trigger.trigchange = 1;
12619 else if(temp_trigflags[0] & 0x00080000) //'prev'
12620 temp_trigger.trigchange = -1;
12621 else temp_trigger.trigchange = 0;
12622 temp_trigflags[0] &= ~(0x00040000|0x00080000);
12623 }
12624 if(section_version >= 29)
12625 {
12626 if(!p_igetw(&temp_trigger.trigprox,f))
12627 {
12628 return qe_invalid;
12629 }
12630 if(!p_getc(&tempbyte,f))
12631 return qe_invalid;
12632 temp_trigger.trigctr = tempbyte;
12633 if(!p_igetl(&temp_trigger.trigctramnt,f))
12634 {
12635 return qe_invalid;
12636 }
12637 }
12638 else
12639 {
12640 temp_trigger.trigprox = 0;
12641 temp_trigger.trigctr = 0;
12642 temp_trigger.trigctramnt = 0;
12643 }
12644 if(section_version >= 30)
12645 {
12646 if(!p_getc(&temp_trigger.triglbeam,f))
12647 {
12648 return qe_invalid;
12649 }
12650 }
12651 else temp_trigger.triglbeam = 0;
12652 if(section_version >= 31)
12653 {
12654 if(!p_getc(&temp_trigger.trigcschange,f))
12655 {
12656 return qe_invalid;
12657 }
12658 if(!p_igetw(&temp_trigger.spawnitem,f))
12659 {
12660 return qe_invalid;
12661 }
12662 if(!p_igetw(&temp_trigger.spawnenemy,f))
12663 {
12664 return qe_invalid;
12665 }
12666 if(!p_getc(&temp_trigger.exstate,f))
12667 {
12668 return qe_invalid;
12669 }
12670 if(!p_igetl(&temp_trigger.spawnip,f))
12671 {
12672 return qe_invalid;
12673 }
12674 if(!p_getc(&temp_trigger.trigcopycat,f))
12675 {
12676 return qe_invalid;
12677 }
12678 }
12679 else
12680 {
12681 temp_trigger.trigcschange = 0;
12682 temp_trigger.spawnitem = 0;
12683 temp_trigger.spawnenemy = 0;
12684 temp_trigger.exstate = -1;
12685 temp_trigger.spawnip = 0;
12686 temp_trigger.trigcopycat = 0;
12687 }
12688 if(section_version >= 32)
12689 {
12690 if(!p_getc(&temp_trigger.trigcooldown,f))
12691 {
12692 return qe_invalid;
12693 }
12694 }
12695 else
12696 {
12697 temp_trigger.trigcooldown = 0;
12698 }
12699 char label[12];
12700 label[11] = '\0';
12701 for ( int32_t q = 0; q < 11; q++ )
12702 {
12703 if(!p_getc(&label[q],f))
12704 {
12705 return 0;
12706 }
12707 }
12708 temp_combo.label = label;
12709 }
12710 if ( section_version >= 13 )
12711 {
12712 for ( int32_t q = 0; q < NUM_COMBO_ATTRIBUTES; q++ )
12713 {
12714 if(!p_getc(&temp_combo.attribytes[q],f))
12715 {
12716 return 0;
12717 }
12718 }
12719
12720 }
12721 }
12722
12723 if ( !(skip && (index+(tilect-1)) < skip) ) //is -1 still needed here?
12724 {
12725 if ( !nooverwrite || combobuf[index+tilect].is_blank() )
12726 {
12727 combobuf[index+(tilect)] = temp_combo;
12728 }
12729 }
12730
12731 temp_trigger.trigger_flags.clear();
12732 for(size_t q = 0; q < 32*3; ++q)
12733 {
12734 auto ind = q/32;
12735 auto bit = 1<<(q%32);
12736 if(temp_trigflags[ind] & bit)
12737 temp_trigger.trigger_flags.set(q, true);
12738 }
12739 }
12740
12741 return 1;
12742 }
12743
12744 int32_t readcombofile(PACKFILE *f, int32_t skip, byte nooverwrite, int32_t start)
12745 {
12746 dword section_version=0;
12747 int32_t zversion = 0;
12748 int32_t zbuild = 0;
12749
12750 if(!p_igetl(&zversion,f))
12751 {
12752 return 0;
12753 }
12754 if(!p_igetl(&zbuild,f))
12755 {
12756 return 0;
12757 }
12758 if(!p_igetw(&section_version,f))
12759 {
12760 return 0;
12761 }
12762 if(!read_deprecated_section_cversion(f))
12763 {
12764 return 0;
12765 }
12766
12767 if ( zversion > ZELDA_VERSION )
12768 {
12769 al_trace("Cannot read .zcombo packfile made in ZC version (%x) in this version of ZC (%x)\n", zversion, ZELDA_VERSION);
12770 return 0;
12771 }
12772
12773 else if ( ( section_version > V_COMBOS ))
12774 {
12775 al_trace("Cannot read .zcombo packfile made using V_COMBOS (%d)\n", section_version);
12776 return 0;
12777
12778 }
12779 else
12780 {
12781 al_trace("Reading a .zcombo packfile made in ZC Version: %x, Build: %d\n", zversion, zbuild);
12782 }
12783
12784 int32_t index = 0;
12785 int32_t count = 0;
12786
12787 //tile id
12788 if(!p_igetl(&index,f))
12789 {
12790 return 0;
12791 }
12792 if(start > -1) index = start;
12793
12794 //tile count
12795 if(!p_igetl(&count,f))
12796 {
12797 return 0;
12798 }
12799 reset_combo_animations();
12800 reset_combo_animations2();
12801
12802 if(section_version < 33)
12803 return readcombofile_old(f,skip,nooverwrite,zversion,section_version,index,count);
12804
12805 newcombo temp_combo;
12806 size_t end = index+count;
12807 for ( size_t q = index; q < end; q++ )
12808 {
12809 auto ret = readcombo_loop(f,section_version,temp_combo);
12810 if(ret) return 0;
12811
12812 if ( !(skip && q-1 < skip) )
12813 {
12814 if ( !nooverwrite || combobuf[q].is_blank() )
12815 {
12816 combobuf[q] = temp_combo;
12817 }
12818 }
12819 }
12820
12821 return 1;
12822 }
12823 int32_t readcombofile_to_location(PACKFILE *f, int32_t start, byte nooverwrite, int32_t skip)
12824 {
12825 return readcombofile(f,skip,nooverwrite,start);
12826 }
12827 int32_t writecombofile(PACKFILE *f, int32_t index, int32_t count)
12828 {
12829 dword section_version=V_COMBOS;
12830 int32_t zversion = ZELDA_VERSION;
12831 int32_t zbuild = VERSION_BUILD;
12832
12833 if(!p_iputl(zversion,f))
12834 {
12835 return 0;
12836 }
12837 if(!p_iputl(zbuild,f))
12838 {
12839 return 0;
12840 }
12841 if(!p_iputw(section_version,f))
12842 {
12843 return 0;
12844 }
12845
12846 if(!write_deprecated_section_cversion(section_version,f))
12847 {
12848 return 0;
12849 }
12850
12851 //start tile id
12852 if(!p_iputl(index,f))
12853 {
12854 return 0;
12855 }
12856
12857 //count
12858 if(!p_iputl(count,f))
12859 {
12860 return 0;
12861 }
12862 reset_combo_animations();
12863 reset_combo_animations2();
12864 size_t end = index+count;
12865 for(size_t q = index; q < end; ++q)
12866 {
12867 if(writecombo_loop(f, section_version, combobuf[q]))
12868 return 0;
12869 }
12870
12871 return 1;
12872
12873 }
12874
12875 //.ZALIAS
12876
12877
12878 //.ZALIAS
12879
12880 int32_t readcomboaliasfile(PACKFILE *f)
12881 {
12882 dword section_version=0;
12883 int32_t zversion = 0;
12884 int32_t zbuild = 0;
12885 word tempword = 0;
12886
12887 if(!p_igetl(&zversion,f))
12888 {
12889 return 0;
12890 }
12891 if(!p_igetl(&zbuild,f))
12892 {
12893 return 0;
12894 }
12895 if(!p_igetw(&section_version,f))
12896 {
12897 return 0;
12898 }
12899 if(!read_deprecated_section_cversion(f))
12900 {
12901 return 0;
12902 }
12903 al_trace("readoneweapon section_version: %d\n", section_version);
12904
12905 if ( zversion > ZELDA_VERSION )
12906 {
12907 al_trace("Cannot read .zalias packfile made in ZC version (%x) in this version of ZC (%x)\n", zversion, ZELDA_VERSION);
12908 return 0;
12909 }
12910
12911 else if ( ( section_version > V_COMBOALIASES ))
12912 {
12913 al_trace("Cannot read .zalias packfile made using V_COMBOALIASES (%d)\n", section_version);
12914 return 0;
12915
12916 }
12917 else
12918 {
12919 al_trace("Reading a .zalias packfile made in ZC Version: %x, Build: %d\n", zversion, zbuild);
12920 }
12921
12922 int32_t index = 0;
12923 int32_t count = 0;
12924 int32_t count2 = 0;
12925 byte tempcset = 0;
12926
12927 //tile id
12928 if(!p_igetl(&index,f))
12929 {
12930 return 0;
12931 }
12932 al_trace("Reading combo: index(%d)\n", index);
12933
12934 //tile count
12935 if(!p_igetl(&count,f))
12936 {
12937 return 0;
12938 }
12939 al_trace("Reading combo: count(%d)\n", count);
12940
12941 combo_alias temp_alias;
12942
12943 for ( int32_t tilect = 0; tilect < count; tilect++ )
12944 {
12945 temp_alias.clear();
12946 if(!p_igetw(&temp_alias.combo,f))
12947 {
12948 return 0;
12949 }
12950
12951 if(!p_getc(&temp_alias.cset,f))
12952 {
12953 return 0;
12954 }
12955
12956
12957
12958 if(!p_igetl(&count2,f))
12959 {
12960 return 0;
12961 }
12962 al_trace("Read, Combo alias count is: %d\n", count2);
12963 if(!p_getc(&temp_alias.width,f))
12964 {
12965 return 0;
12966 }
12967
12968 if(!p_getc(&temp_alias.height,f))
12969 {
12970 return 0;
12971 }
12972
12973 if(!p_getc(&temp_alias.layermask,f))
12974 {
12975 return 0;
12976 }
12977 //These values are flexible, and may differ in size, so we delete them
12978 //and recreate them at the correct size on the pointer.
12979 temp_alias.combos.clear();
12980 temp_alias.csets.clear();
12981 for(int32_t k=0; k<count2; k++)
12982 {
12983 if(!p_igetw(&tempword,f))
12984 {
12985 return 0;
12986 }
12987 else
12988 {
12989
12990
12991 temp_alias.combos[k] = tempword;
12992 }
12993 }
12994
12995 for(int32_t k=0; k<count2; k++)
12996 {
12997 if(!p_getc(&tempcset,f))
12998 //if(!p_getc(&temp_alias.csets[k],f))
12999 {
13000 return 0;
13001 }
13002 else
13003 {
13004
13005 temp_alias.csets[k] = tempcset;
13006 }
13007 }
13008 combo_aliases[index+(tilect)] = temp_alias;
13009 }
13010
13011 //::memcpy(&(newtilebuf[tile_index]),&temptile,sizeof(tiledata));
13012
13013
13014 return 1;
13015
13016 }
13017
13018 int32_t readcomboaliasfile_to_location(PACKFILE *f, int32_t start)
13019 {
13020 dword section_version=0;
13021 int32_t zversion = 0;
13022 int32_t zbuild = 0;
13023
13024 if(!p_igetl(&zversion,f))
13025 {
13026 return 0;
13027 }
13028 if(!p_igetl(&zbuild,f))
13029 {
13030 return 0;
13031 }
13032 if(!p_igetw(&section_version,f))
13033 {
13034 return 0;
13035 }
13036 if(!read_deprecated_section_cversion(f))
13037 {
13038 return 0;
13039 }
13040 al_trace("readcomboaliasfile_to_location section_version: %d\n", section_version);
13041
13042 if ( zversion > ZELDA_VERSION )
13043 {
13044 al_trace("Cannot read .zalias packfile made in ZC version (%x) in this version of ZC (%x)\n", zversion, ZELDA_VERSION);
13045 return 0;
13046 }
13047 else if ( ( section_version > V_COMBOALIASES ))
13048 {
13049 al_trace("Cannot read .zalias packfile made using V_COMBOALIASES (%d)\n", section_version);
13050 return 0;
13051
13052 }
13053 else
13054 {
13055 al_trace("Reading a .zalias packfile made in ZC Version: %x, Build: %d\n", zversion, zbuild);
13056 }
13057
13058 int32_t index = 0;
13059 int32_t count = 0;
13060 int32_t count2 = 0;
13061 byte tempcset = 0;
13062 word tempword = 0;
13063
13064
13065 //tile id
13066 if(!p_igetl(&index,f))
13067 {
13068 return 0;
13069 }
13070 al_trace("Reading tile: index(%d)\n", index);
13071
13072 //tile count
13073 if(!p_igetl(&count,f))
13074 {
13075 return 0;
13076 }
13077 al_trace("Reading tile: count(%d)\n", count);
13078
13079
13080 combo_alias temp_alias;
13081
13082 for ( int32_t tilect = 0; tilect < count; tilect++ )
13083 {
13084 temp_alias.clear();
13085 if(!p_igetw(&temp_alias.combo,f))
13086 {
13087 return 0;
13088 }
13089
13090 if(!p_getc(&temp_alias.cset,f))
13091 {
13092 return 0;
13093 }
13094
13095 int32_t count2 = 0;
13096
13097 if(!p_igetl(&count2,f))
13098 {
13099 return 0;
13100 }
13101
13102 if(!p_getc(&temp_alias.width,f))
13103 {
13104 return 0;
13105 }
13106
13107 if(!p_getc(&temp_alias.height,f))
13108 {
13109 return 0;
13110 }
13111
13112 if(!p_getc(&temp_alias.layermask,f))
13113 {
13114 return 0;
13115 }
13116 //These values are flexible, and may differ in size, so we delete them
13117 //and recreate them at the correct size on the pointer.
13118 temp_alias.combos.clear();
13119 temp_alias.csets.clear();
13120
13121 for(int32_t k=0; k<count2; k++)
13122 {
13123 if(!p_igetw(&tempword,f))
13124 {
13125 return 0;
13126 }
13127 else
13128 {
13129 temp_alias.combos[k] = tempword;
13130 }
13131 }
13132
13133 for(int32_t k=0; k<count2; k++)
13134 {
13135 if(!p_getc(&tempcset,f))
13136 {
13137 return 0;
13138 }
13139 else
13140 {
13141 temp_alias.csets[k] = tempcset;
13142 }
13143 }
13144
13145 if ( start+(tilect) < MAXCOMBOALIASES )
13146 {
13147 combo_aliases[start + (tilect)] = temp_alias;
13148 }
13149 }
13150 return 1;
13151 }
13152 int32_t writecomboaliasfile(PACKFILE *f, int32_t index, int32_t count)
13153 {
13154 al_trace("Running writecomboaliasfile\n");
13155 dword section_version=V_COMBOALIASES;
13156 int32_t zversion = ZELDA_VERSION;
13157 int32_t zbuild = VERSION_BUILD;
13158
13159 if(!p_iputl(zversion,f))
13160 {
13161 return 0;
13162 }
13163 if(!p_iputl(zbuild,f))
13164 {
13165 return 0;
13166 }
13167 if(!p_iputw(section_version,f))
13168 {
13169 return 0;
13170 }
13171
13172 if(!write_deprecated_section_cversion(section_version,f))
13173 {
13174 return 0;
13175 }
13176
13177 //start tile id
13178 if(!p_iputl(index,f))
13179 {
13180 return 0;
13181 }
13182
13183 //count
13184 if(!p_iputl(count,f))
13185 {
13186 return 0;
13187 }
13188
13189 for ( int32_t tilect = 0; tilect < count; tilect++ )
13190 {
13191
13192 if(!p_iputw(combo_aliases[index+(tilect)].combo,f))
13193 {
13194 return 0;
13195 }
13196
13197 if(!p_putc(combo_aliases[index+(tilect)].cset,f))
13198 {
13199 return 0;
13200 }
13201
13202 int32_t count2 = ((combo_aliases[index+(tilect)].width+1)*(combo_aliases[index+(tilect)].height+1))*(comboa_lmasktotal(combo_aliases[index+(tilect)].layermask)+1);
13203
13204 if(!p_iputl(count2,f))
13205 {
13206 return 0;
13207 }
13208 al_trace("Write`, Combo alias count is: %d\n", count2);
13209
13210 if(!p_putc(combo_aliases[index+(tilect)].width,f))
13211 {
13212 return 0;
13213 }
13214
13215 if(!p_putc(combo_aliases[index+(tilect)].height,f))
13216 {
13217 return 0;
13218 }
13219
13220 if(!p_putc(combo_aliases[index+(tilect)].layermask,f))
13221 {
13222 return 0;
13223 }
13224
13225 for(int32_t k=0; k<count2; k++)
13226 {
13227 if(!p_iputw(combo_aliases[index+(tilect)].combos[k],f))
13228 {
13229 return 0;
13230 }
13231 }
13232
13233 for(int32_t k=0; k<count2; k++)
13234 {
13235 if(!p_putc(combo_aliases[index+(tilect)].csets[k],f))
13236 {
13237 return 0;
13238 }
13239 }
13240 }
13241
13242 return 1;
13243
13244 }
13245